Merge branch 'upstream' into tizen_base 91/302891/2 accepted/tizen_base accepted/tizen_base_asan accepted/tizen_base_riscv accepted/tizen_base_toolchain tizen_base accepted/tizen/base/20240104.002451 accepted/tizen/base/asan/20240422.015010 accepted/tizen/base/riscv/20240105.012223 accepted/tizen/base/toolchain/20240124.003911
authorJiyong <jiyong.min@samsung.com>
Fri, 15 Dec 2023 05:09:13 +0000 (14:09 +0900)
committerJiyong <jiyong.min@samsung.com>
Fri, 15 Dec 2023 06:49:44 +0000 (15:49 +0900)
Change-Id: I0338ad087c7e5edf795c6f10b325424af8d7e240

284 files changed:
BUILDING.md
CMakeLists.txt
ChangeLog.md
LICENSE.md
README.ijg
README.md
cdjpeg.h
cjpeg.1
cjpeg.c
cmakescripts/BuildPackages.cmake
cmakescripts/testclean.cmake
cmakescripts/tjbenchtest.cmake [new file with mode: 0644]
cmyk.h
djpeg.c
doc/html/annotated.html
doc/html/classes.html
doc/html/functions.html
doc/html/functions_vars.html
doc/html/group___turbo_j_p_e_g.html
doc/html/index.html
doc/html/modules.html
doc/html/search/all_0.js
doc/html/search/all_6.js
doc/html/search/all_7.js
doc/html/search/all_8.js
doc/html/search/all_9.js
doc/html/search/classes_0.js
doc/html/search/enums_0.js
doc/html/search/enumvalues_0.js
doc/html/search/functions_0.js
doc/html/search/groups_0.js
doc/html/search/typedefs_0.js
doc/html/search/variables_0.js
doc/html/search/variables_1.js
doc/html/search/variables_2.js
doc/html/search/variables_3.js
doc/html/search/variables_4.js
doc/html/search/variables_5.js
doc/html/search/variables_6.js
doc/html/search/variables_7.js
doc/html/search/variables_8.js
doc/html/search/variables_9.js
doc/html/structtjregion.html
doc/html/structtjscalingfactor.html
doc/html/structtjtransform.html
doxygen.config
example.c [moved from example.txt with 59% similarity]
fuzz/CMakeLists.txt
fuzz/build.sh
fuzz/compress.cc
fuzz/compress12.cc [new file with mode: 0644]
fuzz/compress12_lossless.cc [new file with mode: 0644]
fuzz/compress16_lossless.cc [new file with mode: 0644]
fuzz/compress_lossless.cc [new file with mode: 0644]
fuzz/compress_yuv.cc
fuzz/decompress.cc
fuzz/decompress_yuv.cc
fuzz/transform.cc
java/TJBench.java
java/TJExample.java
java/TJUnitTest.java
java/doc/allclasses-frame.html [deleted file]
java/doc/allclasses-index.html [new file with mode: 0644]
java/doc/allclasses.html [moved from java/doc/allclasses-noframe.html with 57% similarity]
java/doc/allpackages-index.html [new file with mode: 0644]
java/doc/constant-values.html
java/doc/deprecated-list.html
java/doc/element-list [moved from java/doc/package-list with 100% similarity]
java/doc/help-doc.html
java/doc/index-all.html
java/doc/index.html
java/doc/jquery-ui.overrides.css [new file with mode: 0644]
java/doc/jquery/external/jquery/jquery.js [new file with mode: 0644]
java/doc/jquery/jquery-3.6.0.min.js [new file with mode: 0644]
java/doc/jquery/jquery-ui.min.css [new file with mode: 0644]
java/doc/jquery/jquery-ui.min.js [new file with mode: 0644]
java/doc/jquery/jszip-utils/dist/jszip-utils-ie.js [new file with mode: 0644]
java/doc/jquery/jszip-utils/dist/jszip-utils-ie.min.js [new file with mode: 0644]
java/doc/jquery/jszip-utils/dist/jszip-utils.js [new file with mode: 0644]
java/doc/jquery/jszip-utils/dist/jszip-utils.min.js [new file with mode: 0644]
java/doc/jquery/jszip/dist/jszip.js [new file with mode: 0644]
java/doc/jquery/jszip/dist/jszip.min.js [new file with mode: 0644]
java/doc/member-search-index.js [new file with mode: 0644]
java/doc/member-search-index.zip [new file with mode: 0644]
java/doc/org/libjpegturbo/turbojpeg/TJ.html
java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
java/doc/org/libjpegturbo/turbojpeg/TJException.html
java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
java/doc/org/libjpegturbo/turbojpeg/YUVImage.html
java/doc/org/libjpegturbo/turbojpeg/package-frame.html [deleted file]
java/doc/org/libjpegturbo/turbojpeg/package-summary.html
java/doc/org/libjpegturbo/turbojpeg/package-tree.html
java/doc/overview-tree.html
java/doc/package-search-index.js [new file with mode: 0644]
java/doc/package-search-index.zip [new file with mode: 0644]
java/doc/resources/background.gif [deleted file]
java/doc/resources/glass.png [new file with mode: 0644]
java/doc/resources/tab.gif [deleted file]
java/doc/resources/titlebar.gif [deleted file]
java/doc/resources/titlebar_end.gif [deleted file]
java/doc/resources/x.png [new file with mode: 0644]
java/doc/script.js
java/doc/search.js [new file with mode: 0644]
java/doc/serialized-form.html
java/doc/stylesheet.css
java/doc/type-search-index.js [new file with mode: 0644]
java/doc/type-search-index.zip [new file with mode: 0644]
java/org/libjpegturbo/turbojpeg/TJ.java
java/org/libjpegturbo/turbojpeg/TJCompressor.java
java/org/libjpegturbo/turbojpeg/TJCustomFilter.java
java/org/libjpegturbo/turbojpeg/TJDecompressor.java
java/org/libjpegturbo/turbojpeg/TJTransform.java
java/org/libjpegturbo/turbojpeg/TJTransformer.java
java/org/libjpegturbo/turbojpeg/YUVImage.java
java/org_libjpegturbo_turbojpeg_TJ.h
java/org_libjpegturbo_turbojpeg_TJCompressor.h
java/org_libjpegturbo_turbojpeg_TJDecompressor.h
java/org_libjpegturbo_turbojpeg_TJTransformer.h
jcapimin.c
jcapistd.c
jccoefct.c
jccolext.c
jccolor.c
jcdctmgr.c
jcdiffct.c [new file with mode: 0644]
jchuff.c
jchuff.h
jcinit.c
jclhuff.c [new file with mode: 0644]
jclossls.c [new file with mode: 0644]
jcmainct.c
jcmarker.c
jcmaster.c
jcmaster.h [new file with mode: 0644]
jconfig.h.in
jconfigint.h.in
jcparam.c
jcphuff.c
jcprepct.c
jcsample.c
jctrans.c
jdapimin.c
jdapistd.c
jdatadst-tj.c
jdatadst.c
jdatasrc-tj.c
jdatasrc.c
jdcoefct.c
jdcoefct.h
jdcol565.c
jdcolext.c
jdcolor.c
jdct.h
jddctmgr.c
jddiffct.c [new file with mode: 0644]
jdhuff.c
jdhuff.h
jdinput.c
jdlhuff.c [new file with mode: 0644]
jdlossls.c [new file with mode: 0644]
jdmainct.c
jdmainct.h
jdmarker.c
jdmaster.c
jdmerge.c
jdmerge.h
jdmrg565.c
jdmrgext.c
jdphuff.c
jdpostct.c
jdsample.c
jdsample.h
jdtrans.c
jerror.h
jfdctfst.c
jfdctint.c
jidctflt.c
jidctfst.c
jidctint.c
jidctred.c
jinclude.h
jlossls.h [new file with mode: 0644]
jmemmgr.c
jmorecfg.h
jpegapicomp.h [moved from jpegcomp.h with 98% similarity]
jpegint.h
jpeglib.h
jquant1.c
jquant2.c
jsamplecomp.h [new file with mode: 0644]
jsimd.h
jsimd_none.c [deleted file]
jutils.c
jversion.h.in
libjpeg.txt
packaging/libjpeg-turbo.spec
rdbmp.c
rdcolmap.c
rdgif.c
rdppm.c
rdtarga.c
release/ReadMe.txt
release/deb-control.in
release/installer.nsi.in
release/rpm.spec.in
sharedlib/CMakeLists.txt
simd/arm/aarch32/jsimd.c
simd/arm/aarch64/jsimd.c
simd/arm/jcphuff-neon.c
simd/arm/jdcolor-neon.c
simd/arm/jdmerge-neon.c
simd/arm/jidctint-neon.c
simd/i386/jsimd.c
simd/jsimd.h
simd/mips/jsimd.c
simd/mips64/jsimd.c
simd/nasm/jsimdext.inc
simd/powerpc/jsimd.c
simd/x86_64/jccolext-avx2.asm
simd/x86_64/jccolext-sse2.asm
simd/x86_64/jcgryext-avx2.asm
simd/x86_64/jcgryext-sse2.asm
simd/x86_64/jchuff-sse2.asm
simd/x86_64/jcphuff-sse2.asm
simd/x86_64/jcsample-avx2.asm
simd/x86_64/jcsample-sse2.asm
simd/x86_64/jdcolext-avx2.asm
simd/x86_64/jdcolext-sse2.asm
simd/x86_64/jdmrgext-avx2.asm
simd/x86_64/jdmrgext-sse2.asm
simd/x86_64/jdsample-avx2.asm
simd/x86_64/jdsample-sse2.asm
simd/x86_64/jfdctflt-sse.asm
simd/x86_64/jfdctfst-sse2.asm
simd/x86_64/jfdctint-avx2.asm
simd/x86_64/jfdctint-sse2.asm
simd/x86_64/jidctflt-sse2.asm
simd/x86_64/jidctfst-sse2.asm
simd/x86_64/jidctint-avx2.asm
simd/x86_64/jidctint-sse2.asm
simd/x86_64/jidctred-sse2.asm
simd/x86_64/jquantf-sse2.asm
simd/x86_64/jquanti-avx2.asm
simd/x86_64/jquanti-sse2.asm
simd/x86_64/jsimd.c
simd/x86_64/jsimdcpu.asm
strtest.c
structure.txt
testimages/big_building16.ppm [new file with mode: 0644]
testimages/big_tree8.bmp [new file with mode: 0644]
testimages/big_tree8.txt [moved from testimages/nightshot_iso_100.txt with 93% similarity]
testimages/nightshot_iso_100.bmp [deleted file]
tjbench.c
tjbenchtest.in
tjbenchtest.java.in [deleted file]
tjexample.c
tjexampletest.in
tjexampletest.java.in [deleted file]
tjunittest.c
transupp.c
turbojpeg-jni.c
turbojpeg-mapfile
turbojpeg-mapfile.jni
turbojpeg-mp.c [new file with mode: 0644]
turbojpeg.c
turbojpeg.h
usage.txt
win/jconfig.h.in [deleted file]
win/jpeg.rc.in
win/jpeg62-memsrcdst.def [deleted file]
win/jpeg62.def
win/jpeg7-memsrcdst.def [deleted file]
win/jpeg7.def
win/jpeg8.def
win/turbojpeg.rc.in
wizard.txt
wrbmp.c
wrgif.c
wrppm.c
wrtarga.c

index 2ce65d6..6b484a1 100644 (file)
@@ -25,9 +25,9 @@ Build Requirements
     variable or the `ASM_NASM` environment variable.  On Windows, use forward
     slashes rather than backslashes in the path (for example,
     **c:/nasm/nasm.exe**).
-  * NASM and Yasm are located in the CRB (Code Ready Builder) repository on
-    Red Hat Enterprise Linux 8 and in the PowerTools repository on RHEL
-    derivatives, which is not enabled by default.
+  * NASM and Yasm are located in the CRB (Code Ready Builder) or PowerTools
+    repository on Red Hat Enterprise Linux 8+ and derivatives, which is not
+    enabled by default.
 
 ### Un*x Platforms (including Linux, Mac, FreeBSD, Solaris, and Cygwin)
 
@@ -288,15 +288,6 @@ API/ABI-compatible with libjpeg v8.  See [README.md](README.md) for more
 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
@@ -372,9 +363,13 @@ located (usually **/usr/bin**.)  Next, execute the following commands:
 
     cd {build_directory}
     cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
+      -DCMAKE_INSTALL_PREFIX={install_path} \
       [additional CMake flags] {source_directory}
     make
 
+*{install\_path}* is the path under which the libjpeg-turbo binaries should be
+installed.
+
 
 ### 64-bit MinGW Build on Un*x (including Mac and Cygwin)
 
@@ -391,9 +386,13 @@ located (usually **/usr/bin**.)  Next, execute the following commands:
 
     cd {build_directory}
     cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
+      -DCMAKE_INSTALL_PREFIX={install_path} \
       [additional CMake flags] {source_directory}
     make
 
+*{install\_path}* is the path under which the libjpeg-turbo binaries should be
+installed.
+
 
 Building libjpeg-turbo for iOS
 ------------------------------
@@ -429,6 +428,10 @@ iPhone 5S/iPad Mini 2/iPad Air and newer.
       [additional CMake flags] {source_directory}
     make
 
+Replace `iPhoneOS` with `iPhoneSimulator` and `-miphoneos-version-min` with
+`-miphonesimulator-version-min` to build libjpeg-turbo for the iOS simulator on
+Macs with Apple silicon CPUs.
+
 
 Building libjpeg-turbo for Android
 ----------------------------------
index 09223de..e80ca9e 100644 (file)
@@ -10,8 +10,8 @@ if(CMAKE_EXECUTABLE_SUFFIX)
 endif()
 
 project(libjpeg-turbo C)
-set(VERSION 2.1.4)
-set(COPYRIGHT_YEAR "1991-2022")
+set(VERSION 3.0.1)
+set(COPYRIGHT_YEAR "1991-2023")
 string(REPLACE "." ";" VERSION_TRIPLET ${VERSION})
 list(GET VERSION_TRIPLET 0 VERSION_MAJOR)
 list(GET VERSION_TRIPLET 1 VERSION_MINOR)
@@ -31,6 +31,34 @@ pad_number(VERSION_MINOR 3)
 pad_number(VERSION_REVISION 3)
 set(LIBJPEG_TURBO_VERSION_NUMBER ${VERSION_MAJOR}${VERSION_MINOR}${VERSION_REVISION})
 
+# The libjpeg-turbo build system has never supported and will never support
+# being integrated into another build system using add_subdirectory(), because
+# doing so would require that we (minimally):
+#
+# 1. avoid using certain CMake variables, such as CMAKE_SOURCE_DIR,
+#    CMAKE_BINARY_DIR, and CMAKE_PROJECT_NAME;
+# 2. avoid using implicit include directories and relative paths;
+# 3. optionally provide a way to skip the installation of libjpeg-turbo
+#    components when the 'install' target is built;
+# 4. optionally provide a way to postfix target names, to avoid namespace
+#    conflicts;
+# 5. restructure the top-level CMakeLists.txt so that it properly sets the
+#    PROJECT_VERSION variable; and
+# 6. design automated regression tests to ensure that new commits don't break
+#    any of the above.
+#
+# Even if we did all of that, issues would still arise, because it is
+# impossible for an upstream build system to anticipate the widely varying
+# needs of every downstream build system.  That's why the CMake
+# ExternalProject_Add() function exists.  Downstream projects that wish to
+# integrate libjpeg-turbo as a subdirectory should either use
+# ExternalProject_Add() or make downstream modifications to the libjpeg-turbo
+# build system to suit their specific needs.  Please do not file bug reports,
+# feature requests, or pull requests regarding this.
+if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+  message(FATAL_ERROR "The libjpeg-turbo build system cannot be integrated into another build system using add_subdirectory().  Use ExternalProject_Add() instead.")
+endif()
+
 # CMake 3.14 and later sets CMAKE_MACOSX_BUNDLE to TRUE by default when
 # CMAKE_SYSTEM_NAME is iOS, tvOS, or watchOS, which breaks the libjpeg-turbo
 # build.  (Specifically, when CMAKE_MACOSX_BUNDLE is TRUE, executables for
@@ -40,6 +68,15 @@ set(LIBJPEG_TURBO_VERSION_NUMBER ${VERSION_MAJOR}${VERSION_MINOR}${VERSION_REVIS
 # application bundles would break our iOS packages.)
 set(CMAKE_MACOSX_BUNDLE FALSE)
 
+get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY
+  GENERATOR_IS_MULTI_CONFIG)
+# If the GENERATOR_IS_MULTI_CONFIG property doesn't exist (CMake < 3.9), then
+# set the GENERATOR_IS_MULTI_CONFIG variable manually if the generator is
+# Visual Studio or Xcode (the only multi-config generators in CMake < 3.9).
+if(NOT GENERATOR_IS_MULTI_CONFIG AND (MSVC_IDE OR XCODE))
+  set(GENERATOR_IS_MULTI_CONFIG TRUE)
+endif()
+
 string(TIMESTAMP DEFAULT_BUILD "%Y%m%d")
 set(BUILD ${DEFAULT_BUILD} CACHE STRING "Build string (default: ${DEFAULT_BUILD})")
 
@@ -61,7 +98,7 @@ string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR_LC)
 set(COUNT 1)
 foreach(ARCH ${CMAKE_OSX_ARCHITECTURES})
   if(COUNT GREATER 1)
-    message(FATAL_ERROR "The libjpeg-turbo build system does not support multiple values in CMAKE_OSX_ARCHITECTURES.")
+    message(FATAL_ERROR "libjpeg-turbo contains assembly code, so it cannot be built with multiple values in CMAKE_OSX_ARCHITECTURES.")
   endif()
   math(EXPR COUNT "${COUNT}+1")
 endforeach()
@@ -187,8 +224,6 @@ option(ENABLE_STATIC "Build static libraries" TRUE)
 boolean_number(ENABLE_STATIC)
 option(REQUIRE_SIMD "Generate a fatal error if SIMD extensions are not available for this platform (default is to fall back to a non-SIMD build)" FALSE)
 boolean_number(REQUIRE_SIMD)
-option(WITH_12BIT "Encode/decode JPEG images with 12-bit samples (implies WITH_ARITH_DEC=0 WITH_ARITH_ENC=0 WITH_JAVA=0 WITH_SIMD=0 WITH_TURBOJPEG=0 )" FALSE)
-boolean_number(WITH_12BIT)
 option(WITH_ARITH_DEC "Include arithmetic decoding support when emulating the libjpeg v6b API/ABI" TRUE)
 boolean_number(WITH_ARITH_DEC)
 option(WITH_ARITH_ENC "Include arithmetic encoding support when emulating the libjpeg v6b API/ABI" TRUE)
@@ -203,8 +238,6 @@ option(WITH_JPEG7 "Emulate libjpeg v7 API/ABI (this makes ${CMAKE_PROJECT_NAME}
 boolean_number(WITH_JPEG7)
 option(WITH_JPEG8 "Emulate libjpeg v8 API/ABI (this makes ${CMAKE_PROJECT_NAME} backward-incompatible with libjpeg v6b)" FALSE)
 boolean_number(WITH_JPEG8)
-option(WITH_MEM_SRCDST "Include in-memory source/destination manager functions when emulating the libjpeg v6b or v7 API/ABI" TRUE)
-boolean_number(WITH_MEM_SRCDST)
 option(WITH_SIMD "Include SIMD extensions, if available for this platform" TRUE)
 boolean_number(WITH_SIMD)
 option(WITH_TURBOJPEG "Include the TurboJPEG API library and associated test programs" TRUE)
@@ -246,52 +279,39 @@ if(WITH_JPEG8 OR WITH_JPEG7)
   set(WITH_ARITH_ENC 1)
   set(WITH_ARITH_DEC 1)
 endif()
-if(WITH_JPEG8)
-  set(WITH_MEM_SRCDST 0)
-endif()
-
-if(WITH_12BIT)
-  set(WITH_ARITH_DEC 0)
-  set(WITH_ARITH_ENC 0)
-  set(WITH_JAVA 0)
-  set(WITH_SIMD 0)
-  set(WITH_TURBOJPEG 0)
-  set(BITS_IN_JSAMPLE 12)
-else()
-  set(BITS_IN_JSAMPLE 8)
-endif()
-report_option(WITH_12BIT "12-bit JPEG support")
 
 if(WITH_ARITH_DEC)
   set(D_ARITH_CODING_SUPPORTED 1)
 endif()
-if(NOT WITH_12BIT)
-  report_option(WITH_ARITH_DEC "Arithmetic decoding support")
-endif()
+report_option(WITH_ARITH_DEC "Arithmetic decoding support")
 
 if(WITH_ARITH_ENC)
   set(C_ARITH_CODING_SUPPORTED 1)
 endif()
-if(NOT WITH_12BIT)
-  report_option(WITH_ARITH_ENC "Arithmetic encoding support")
-endif()
+report_option(WITH_ARITH_ENC "Arithmetic encoding support")
 
-if(NOT WITH_12BIT)
-  report_option(WITH_TURBOJPEG "TurboJPEG API library")
-  report_option(WITH_JAVA "TurboJPEG Java wrapper")
-endif()
+report_option(WITH_TURBOJPEG "TurboJPEG API library")
+report_option(WITH_JAVA "TurboJPEG Java wrapper")
 
-if(WITH_MEM_SRCDST)
-  set(MEM_SRCDST_SUPPORTED 1)
-  set(MEM_SRCDST_FUNCTIONS "global:  jpeg_mem_dest;  jpeg_mem_src;")
-endif()
 if(NOT WITH_JPEG8)
-  report_option(WITH_MEM_SRCDST "In-memory source/destination managers")
+  set(MEM_SRCDST_FUNCTIONS "global:  jpeg_mem_dest;  jpeg_mem_src;")
 endif()
 
-set(SO_AGE 2)
-if(WITH_MEM_SRCDST)
-  set(SO_AGE 3)
+# 0: Original libjpeg v6b/v7/v8 API/ABI
+#
+# libjpeg v6b/v7 API/ABI emulation:
+# 1: + In-memory source/destination managers (libjpeg-turbo 1.3.x)
+# 2: + Partial image decompression functions (libjpeg-turbo 1.5.x)
+# 3: + ICC functions (libjpeg-turbo 2.0.x)
+# 4: + 12-bit-per-component and lossless functions (libjpeg-turbo 2.2.x)
+#
+# libjpeg v8 API/ABI emulation:
+# 1: + Partial image decompression functions (libjpeg-turbo 1.5.x)
+# 2: + ICC functions (libjpeg-turbo 2.0.x)
+# 3: + 12-bit-per-component and lossless functions (libjpeg-turbo 2.2.x)
+set(SO_AGE 3)
+if(NOT WITH_JPEG8)
+  set(SO_AGE 4)
 endif()
 
 if(WITH_JPEG8)
@@ -345,9 +365,21 @@ message(STATUS "libjpeg API shared library version = ${SO_MAJOR_VERSION}.${SO_AG
 # names of functions whenever they are modified in a backward-incompatible
 # manner, it is always backward-ABI-compatible with itself, so the major and
 # minor SO versions don't change.  However, we increase the middle number (the
-# SO "age") whenever functions are added to the API.
+# SO "age") whenever functions are added to the API, because adding functions
+# affects forward API/ABI compatibility.
 set(TURBOJPEG_SO_MAJOR_VERSION 0)
-set(TURBOJPEG_SO_AGE 2)
+# 0: TurboJPEG 1.3.x API
+# 1: TurboJPEG 1.4.x API
+#    The TurboJPEG 1.5.x API modified some of the function prototypes, adding
+#    the const keyword in front of pointers to unmodified buffers, but that did
+#    not affect forward API/ABI compatibility.
+# 2: TurboJPEG 2.0.x API
+#    The TurboJPEG 2.1.x API modified the behavior of the tjDecompressHeader3()
+#    function so that it accepts "abbreviated table specification" (AKA
+#    "tables-only") datastreams as well as JPEG images, but that did not affect
+#    forward API/ABI compatibility.
+# 3: TurboJPEG 3 API
+set(TURBOJPEG_SO_AGE 3)
 set(TURBOJPEG_SO_VERSION 0.${TURBOJPEG_SO_AGE}.0)
 
 
@@ -472,19 +504,17 @@ if(NOT INLINE_WORKS)
 endif()
 message(STATUS "INLINE = ${INLINE} (FORCE_INLINE = ${FORCE_INLINE})")
 
-if(WITH_TURBOJPEG)
-  if(MSVC)
-    set(THREAD_LOCAL "__declspec(thread)")
-  else()
-    set(THREAD_LOCAL "__thread")
-  endif()
-  check_c_source_compiles("${THREAD_LOCAL} int i;  int main(void) { i = 0;  return i; }" HAVE_THREAD_LOCAL)
-  if(HAVE_THREAD_LOCAL)
-    message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}")
-  else()
-    message(WARNING "Thread-local storage is not available.  The TurboJPEG API library's global error handler will not be thread-safe.")
-    unset(THREAD_LOCAL)
-  endif()
+if(MSVC)
+  set(THREAD_LOCAL "__declspec(thread)")
+else()
+  set(THREAD_LOCAL "__thread")
+endif()
+check_c_source_compiles("${THREAD_LOCAL} int i;  int main(void) { i = 0;  return i; }" HAVE_THREAD_LOCAL)
+if(HAVE_THREAD_LOCAL)
+  message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}")
+else()
+  message(WARNING "Thread-local storage is not available.  The TurboJPEG API library's global error handler will not be thread-safe.")
+  unset(THREAD_LOCAL)
 endif()
 
 if(UNIX AND NOT APPLE)
@@ -522,12 +552,6 @@ if(UNIX AND NOT APPLE)
 endif()
 
 # Generate files
-if(WIN32)
-  configure_file(win/jconfig.h.in jconfig.h)
-else()
-  configure_file(jconfig.h.in jconfig.h)
-endif()
-configure_file(jconfigint.h.in jconfigint.h)
 configure_file(jversion.h.in jversion.h)
 if(UNIX)
   configure_file(libjpeg.map.in libjpeg.map)
@@ -546,13 +570,17 @@ if(CMAKE_EXECUTABLE_SUFFIX_TMP)
 endif()
 message(STATUS "CMAKE_EXECUTABLE_SUFFIX = ${CMAKE_EXECUTABLE_SUFFIX}")
 
-set(JPEG_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 jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c)
+set(JPEG16_SOURCES jcapistd.c jccolor.c jcdiffct.c jclossls.c jcmainct.c
+  jcprepct.c jcsample.c jdapistd.c jdcolor.c jddiffct.c jdlossls.c jdmainct.c
+  jdpostct.c jdsample.c jutils.c)
+set(JPEG12_SOURCES ${JPEG16_SOURCES} jccoefct.c jcdctmgr.c jdcoefct.c
+  jddctmgr.c jdmerge.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c
+  jidctred.c jquant1.c jquant2.c)
+set(JPEG_SOURCES ${JPEG12_SOURCES} jcapimin.c jchuff.c jcicc.c jcinit.c
+  jclhuff.c jcmarker.c jcmaster.c jcomapi.c jcparam.c jcphuff.c jctrans.c
+  jdapimin.c jdatadst.c jdatasrc.c jdhuff.c jdicc.c jdinput.c jdlhuff.c
+  jdmarker.c jdmaster.c jdphuff.c jdtrans.c jerror.c jfdctflt.c jmemmgr.c
+  jmemnobs.c)
 
 if(WITH_ARITH_ENC OR WITH_ARITH_DEC)
   set(JPEG_SOURCES ${JPEG_SOURCES} jaricom.c)
@@ -571,19 +599,21 @@ if(WITH_SIMD)
   if(NEON_INTRINSICS)
     add_definitions(-DNEON_INTRINSICS)
   endif()
-elseif(NOT WITH_12BIT)
+else()
   message(STATUS "SIMD extensions: None (WITH_SIMD = ${WITH_SIMD})")
 endif()
+
+# We have to generate these here, because if the build system tries and fails
+# to enable the SIMD extensions, the value of WITH_SIMD will have changed.
+configure_file(jconfig.h.in jconfig.h)
+configure_file(jconfigint.h.in jconfigint.h)
+
 if(WITH_SIMD)
   message(STATUS "SIMD extensions: ${CPU_TYPE} (WITH_SIMD = ${WITH_SIMD})")
   if(MSVC_IDE OR XCODE)
     set_source_files_properties(${SIMD_OBJS} PROPERTIES GENERATED 1)
   endif()
-else()
-  add_library(simd OBJECT jsimd_none.c)
-  if(NOT WIN32 AND (CMAKE_POSITION_INDEPENDENT_CODE OR ENABLE_SHARED))
-    set_target_properties(simd PROPERTIES POSITION_INDEPENDENT_CODE 1)
-  endif()
+  set(SIMD_TARGET_OBJECTS $<TARGET_OBJECTS:simd>)
 endif()
 
 if(WITH_JAVA)
@@ -591,12 +621,29 @@ if(WITH_JAVA)
 endif()
 
 if(ENABLE_SHARED)
+  # Compile a separate version of these source files with 12-bit and 16-bit
+  # data precision.
+  add_library(jpeg12 OBJECT ${JPEG12_SOURCES})
+  set_property(TARGET jpeg12 PROPERTY COMPILE_FLAGS "-DBITS_IN_JSAMPLE=12")
+  set_target_properties(jpeg12 PROPERTIES POSITION_INDEPENDENT_CODE 1)
+  add_library(jpeg16 OBJECT ${JPEG16_SOURCES})
+  set_property(TARGET jpeg16 PROPERTY COMPILE_FLAGS "-DBITS_IN_JSAMPLE=16")
+  set_target_properties(jpeg16 PROPERTIES POSITION_INDEPENDENT_CODE 1)
   add_subdirectory(sharedlib)
 endif()
 
 if(ENABLE_STATIC)
-  add_library(jpeg-static STATIC ${JPEG_SOURCES} $<TARGET_OBJECTS:simd>
-    ${SIMD_OBJS})
+  # Compile a separate version of these source files with 12-bit and 16-bit
+  # data precision.
+  add_library(jpeg12-static OBJECT ${JPEG12_SOURCES})
+  set_property(TARGET jpeg12-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=12")
+  add_library(jpeg16-static OBJECT ${JPEG16_SOURCES})
+  set_property(TARGET jpeg16-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=16")
+  add_library(jpeg-static STATIC ${JPEG_SOURCES} ${SIMD_TARGET_OBJECTS}
+    ${SIMD_OBJS} $<TARGET_OBJECTS:jpeg12-static>
+    $<TARGET_OBJECTS:jpeg16-static>)
   if(NOT MSVC)
     set_target_properties(jpeg-static PROPERTIES OUTPUT_NAME jpeg)
   endif()
@@ -604,9 +651,9 @@ endif()
 
 if(WITH_TURBOJPEG)
   if(ENABLE_SHARED)
-    set(TURBOJPEG_SOURCES ${JPEG_SOURCES} $<TARGET_OBJECTS:simd> ${SIMD_OBJS}
+    set(TURBOJPEG_SOURCES ${JPEG_SOURCES} ${SIMD_TARGET_OBJECTS} ${SIMD_OBJS}
       turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c rdbmp.c rdppm.c
-      wrbmp.c wrppm.c)
+      wrbmp.c wrppm.c $<TARGET_OBJECTS:jpeg12> $<TARGET_OBJECTS:jpeg16>)
     set(TJMAPFILE ${CMAKE_CURRENT_SOURCE_DIR}/turbojpeg-mapfile)
     if(WITH_JAVA)
       set(TURBOJPEG_SOURCES ${TURBOJPEG_SOURCES} turbojpeg-jni.c)
@@ -619,7 +666,16 @@ if(WITH_TURBOJPEG)
       set(TURBOJPEG_SOURCES ${TURBOJPEG_SOURCES}
         ${CMAKE_BINARY_DIR}/win/turbojpeg.rc)
     endif()
-    add_library(turbojpeg SHARED ${TURBOJPEG_SOURCES})
+    add_library(turbojpeg12 OBJECT rdppm.c wrppm.c)
+    set_property(TARGET turbojpeg12 PROPERTY COMPILE_FLAGS
+      "-DBITS_IN_JSAMPLE=12 -DPPM_SUPPORTED")
+    set_target_properties(turbojpeg12 PROPERTIES POSITION_INDEPENDENT_CODE 1)
+    add_library(turbojpeg16 OBJECT rdppm.c wrppm.c)
+    set_property(TARGET turbojpeg16 PROPERTY COMPILE_FLAGS
+      "-DBITS_IN_JSAMPLE=16 -DPPM_SUPPORTED")
+    set_target_properties(turbojpeg16 PROPERTIES POSITION_INDEPENDENT_CODE 1)
+    add_library(turbojpeg SHARED ${TURBOJPEG_SOURCES}
+      $<TARGET_OBJECTS:turbojpeg12> $<TARGET_OBJECTS:turbojpeg16>)
     set_property(TARGET turbojpeg PROPERTY COMPILE_FLAGS
       "-DBMP_SUPPORTED -DPPM_SUPPORTED")
     if(WIN32)
@@ -656,9 +712,17 @@ if(WITH_TURBOJPEG)
   endif()
 
   if(ENABLE_STATIC)
-    add_library(turbojpeg-static STATIC ${JPEG_SOURCES} $<TARGET_OBJECTS:simd>
+    add_library(turbojpeg12-static OBJECT rdppm.c wrppm.c)
+    set_property(TARGET turbojpeg12-static PROPERTY COMPILE_FLAGS
+      "-DBITS_IN_JSAMPLE=12 -DPPM_SUPPORTED")
+    add_library(turbojpeg16-static OBJECT rdppm.c wrppm.c)
+    set_property(TARGET turbojpeg16-static PROPERTY COMPILE_FLAGS
+      "-DBITS_IN_JSAMPLE=16 -DPPM_SUPPORTED")
+    add_library(turbojpeg-static STATIC ${JPEG_SOURCES} ${SIMD_TARGET_OBJECTS}
       ${SIMD_OBJS} turbojpeg.c transupp.c jdatadst-tj.c jdatasrc-tj.c rdbmp.c
-      rdppm.c wrbmp.c wrppm.c)
+      rdppm.c wrbmp.c wrppm.c $<TARGET_OBJECTS:jpeg12-static>
+      $<TARGET_OBJECTS:jpeg16-static> $<TARGET_OBJECTS:turbojpeg12-static>
+      $<TARGET_OBJECTS:turbojpeg16-static>)
     set_property(TARGET turbojpeg-static PROPERTY COMPILE_FLAGS
       "-DBMP_SUPPORTED -DPPM_SUPPORTED")
     if(NOT MSVC)
@@ -680,28 +744,46 @@ endif()
 if(WIN32)
   set(USE_SETMODE "-DUSE_SETMODE")
 endif()
-if(WITH_12BIT)
-  set(COMPILE_FLAGS "-DGIF_SUPPORTED -DPPM_SUPPORTED ${USE_SETMODE}")
-else()
-  set(COMPILE_FLAGS "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED ${USE_SETMODE}")
-  set(CJPEG_BMP_SOURCES rdbmp.c rdtarga.c)
-  set(DJPEG_BMP_SOURCES wrbmp.c wrtarga.c)
-endif()
+set(CDJPEG_COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED ${USE_SETMODE}")
 
 if(ENABLE_STATIC)
-  add_executable(cjpeg-static cjpeg.c cdjpeg.c rdgif.c rdppm.c rdswitch.c
-    ${CJPEG_BMP_SOURCES})
-  set_property(TARGET cjpeg-static PROPERTY COMPILE_FLAGS ${COMPILE_FLAGS})
+  # Compile a separate version of these source files with 12-bit and 16-bit
+  # data precision.
+  add_library(cjpeg12-static OBJECT rdgif.c rdppm.c)
+  set_property(TARGET cjpeg12-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=12 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+  add_library(cjpeg16-static OBJECT rdgif.c rdppm.c)
+  set_property(TARGET cjpeg16-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=16 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+  add_executable(cjpeg-static cjpeg.c cdjpeg.c rdbmp.c rdgif.c rdppm.c
+    rdswitch.c rdtarga.c $<TARGET_OBJECTS:cjpeg12-static>
+    $<TARGET_OBJECTS:cjpeg16-static>)
+  set_property(TARGET cjpeg-static PROPERTY COMPILE_FLAGS
+    ${CDJPEG_COMPILE_FLAGS})
   target_link_libraries(cjpeg-static jpeg-static)
 
-  add_executable(djpeg-static djpeg.c cdjpeg.c rdcolmap.c rdswitch.c wrgif.c
-    wrppm.c ${DJPEG_BMP_SOURCES})
-  set_property(TARGET djpeg-static PROPERTY COMPILE_FLAGS ${COMPILE_FLAGS})
+  # Compile a separate version of these source files with 12-bit and 16-bit
+  # data precision.
+  add_library(djpeg12-static OBJECT rdcolmap.c wrgif.c wrppm.c)
+  set_property(TARGET djpeg12-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=12 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+  add_library(djpeg16-static OBJECT wrppm.c)
+  set_property(TARGET djpeg16-static PROPERTY COMPILE_FLAGS
+    "-DBITS_IN_JSAMPLE=16 -DPPM_SUPPORTED")
+  add_executable(djpeg-static djpeg.c cdjpeg.c rdcolmap.c rdswitch.c wrbmp.c
+    wrgif.c wrppm.c wrtarga.c $<TARGET_OBJECTS:djpeg12-static>
+    $<TARGET_OBJECTS:djpeg16-static>)
+  set_property(TARGET djpeg-static PROPERTY COMPILE_FLAGS
+    ${CDJPEG_COMPILE_FLAGS})
   target_link_libraries(djpeg-static jpeg-static)
 
   add_executable(jpegtran-static jpegtran.c cdjpeg.c rdswitch.c transupp.c)
   target_link_libraries(jpegtran-static jpeg-static)
   set_property(TARGET jpegtran-static PROPERTY COMPILE_FLAGS "${USE_SETMODE}")
+
+  add_executable(example-static example.c)
+  target_link_libraries(example-static jpeg-static)
 endif()
 
 add_executable(rdjpgcom rdjpgcom.c)
@@ -721,7 +803,7 @@ add_executable(strtest strtest.c)
 
 add_subdirectory(md5)
 
-if(MSVC_IDE OR XCODE)
+if(GENERATOR_IS_MULTI_CONFIG)
   set(OBJDIR "\${CTEST_CONFIGURATION_TYPE}/")
 else()
   set(OBJDIR "")
@@ -729,124 +811,6 @@ endif()
 
 enable_testing()
 
-if(WITH_12BIT)
-  set(TESTORIG testorig12.jpg)
-  set(MD5_JPEG_RGB_ISLOW 9d7369207c520d37f2c1cbfcb82b2964)
-  set(MD5_JPEG_RGB_ISLOW2 a00bd20d8ae49684640ef7177d2e0b64)
-  set(MD5_PPM_RGB_ISLOW f3301d2219783b8b3d942b7239fa50c0)
-  set(MD5_JPEG_422_IFAST_OPT 7322e3bd2f127f7de4b40d4480ce60e4)
-  set(MD5_PPM_422_IFAST 79807fa552899e66a04708f533e16950)
-  set(MD5_JPEG_440_ISLOW e25c1912e38367be505a89c410c1c2d2)
-  set(MD5_PPM_440_ISLOW e7d2e26288870cfcb30f3114ad01e380)
-  set(MD5_PPM_422M_IFAST 07737bfe8a7c1c87aaa393a0098d16b0)
-  set(MD5_JPEG_420_IFAST_Q100_PROG 9447cef4803d9b0f74bcf333cc710a29)
-  set(MD5_PPM_420_Q100_IFAST 1b3730122709f53d007255e8dfd3305e)
-  set(MD5_PPM_420M_Q100_IFAST 980a1a3c5bf9510022869d30b7d26566)
-  set(MD5_JPEG_GRAY_ISLOW 235c90707b16e2e069f37c888b2636d9)
-  set(MD5_PPM_GRAY_ISLOW 7213c10af507ad467da5578ca5ee1fca)
-  set(MD5_PPM_GRAY_ISLOW_RGB e96ee81c30a6ed422d466338bd3de65d)
-  set(MD5_JPEG_420S_IFAST_OPT 7af8e60be4d9c227ec63ac9b6630855e)
-
-  set(MD5_JPEG_3x2_FLOAT_PROG_SSE a8c17daf77b457725ec929e215b603f8)
-  set(MD5_PPM_3x2_FLOAT_SSE 42876ab9e5c2f76a87d08db5fbd57956)
-  set(MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT a8c17daf77b457725ec929e215b603f8)
-  set(MD5_PPM_3x2_FLOAT_NO_FP_CONTRACT ${MD5_PPM_3x2_FLOAT_SSE})
-  set(MD5_JPEG_3x2_FLOAT_PROG_FP_CONTRACT
-    ${MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT})
-  set(MD5_PPM_3x2_FLOAT_FP_CONTRACT ${MD5_PPM_3x2_FLOAT_SSE})
-  set(MD5_JPEG_3x2_FLOAT_PROG_387 bc6dbbefac2872f6b9d6c4a0ae60c3c0)
-  set(MD5_PPM_3x2_FLOAT_387 bcc5723c61560463ac60f772e742d092)
-  set(MD5_JPEG_3x2_FLOAT_PROG_MSVC e27840755870fa849872e58aa0cd1400)
-  set(MD5_PPM_3x2_FLOAT_MSVC 6c2880b83bb1aa41dfe330e7a9768690)
-
-  set(MD5_JPEG_3x2_IFAST_PROG 1396cc2b7185cfe943d408c9d305339e)
-  set(MD5_PPM_3x2_IFAST 3975985ef6eeb0a2cdc58daa651ccc00)
-  set(MD5_PPM_420M_ISLOW_2_1 4ca6be2a6f326ff9eaab63e70a8259c0)
-  set(MD5_PPM_420M_ISLOW_15_8 12aa9f9534c1b3d7ba047322226365eb)
-  set(MD5_PPM_420M_ISLOW_13_8 f7e22817c7b25e1393e4ec101e9d4e96)
-  set(MD5_PPM_420M_ISLOW_11_8 800a16f9f4dc9b293197bfe11be10a82)
-  set(MD5_PPM_420M_ISLOW_9_8 06b7a92a9bc69f4dc36ec40f1937d55c)
-  set(MD5_PPM_420M_ISLOW_7_8 3ec444a14a4ab4eab88ffc49c48eca43)
-  set(MD5_PPM_420M_ISLOW_3_4 3e726b7ea872445b19437d1c1d4f0d93)
-  set(MD5_PPM_420M_ISLOW_5_8 a8a771abdc94301d20ffac119b2caccd)
-  set(MD5_PPM_420M_ISLOW_1_2 b419124dd5568b085787234866102866)
-  set(MD5_PPM_420M_ISLOW_3_8 343d19015531b7bbe746124127244fa8)
-  set(MD5_PPM_420M_ISLOW_1_4 35fd59d866e44659edfa3c18db2a3edb)
-  set(MD5_PPM_420M_ISLOW_1_8 ccaed48ac0aedefda5d4abe4013f4ad7)
-  set(MD5_PPM_420_ISLOW_SKIP15_31 86664cd9dc956536409e44e244d20a97)
-  set(MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71 452a21656115a163029cfba5c04fa76a)
-  set(MD5_PPM_444_ISLOW_SKIP1_6 ef63901f71ef7a75cd78253fc0914f84)
-  set(MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13 15b173fb5872d9575572fbcc1b05956f)
-  set(MD5_JPEG_CROP cdb35ff4b4519392690ea040c56ea99c)
-else()
-  set(TESTORIG testorig.jpg)
-  set(MD5_JPEG_RGB_ISLOW 1d44a406f61da743b5fd31c0a9abdca3)
-  set(MD5_JPEG_RGB_ISLOW2 31d121e57b6c2934c890a7fc7763bcd4)
-  set(MD5_PPM_RGB_ISLOW 00a257f5393fef8821f2b88ac7421291)
-  set(MD5_BMP_RGB_ISLOW_565 f07d2e75073e4bb10f6c6f4d36e2e3be)
-  set(MD5_BMP_RGB_ISLOW_565D 4cfa0928ef3e6bb626d7728c924cfda4)
-  set(MD5_JPEG_422_IFAST_OPT 2540287b79d913f91665e660303ab2c8)
-  set(MD5_PPM_422_IFAST 35bd6b3f833bad23de82acea847129fa)
-  set(MD5_JPEG_440_ISLOW 538bc02bd4b4658fd85de6ece6cbeda6)
-  set(MD5_PPM_440_ISLOW 11e7eab7ef7ef3276934bb7e7b6bb377)
-  set(MD5_PPM_422M_IFAST 8dbc65323d62cca7c91ba02dd1cfa81d)
-  set(MD5_BMP_422M_IFAST_565 3294bd4d9a1f2b3d08ea6020d0db7065)
-  set(MD5_BMP_422M_IFAST_565D da98c9c7b6039511be4a79a878a9abc1)
-  set(MD5_JPEG_420_IFAST_Q100_PROG 0ba15f9dab81a703505f835f9dbbac6d)
-  set(MD5_PPM_420_Q100_IFAST 5a732542015c278ff43635e473a8a294)
-  set(MD5_PPM_420M_Q100_IFAST ff692ee9323a3b424894862557c092f1)
-  set(MD5_JPEG_GRAY_ISLOW 72b51f894b8f4a10b3ee3066770aa38d)
-  set(MD5_PPM_GRAY_ISLOW 8d3596c56eace32f205deccc229aa5ed)
-  set(MD5_PPM_GRAY_ISLOW_RGB 116424ac07b79e5e801f00508eab48ec)
-  set(MD5_BMP_GRAY_ISLOW_565 12f78118e56a2f48b966f792fedf23cc)
-  set(MD5_BMP_GRAY_ISLOW_565D bdbbd616441a24354c98553df5dc82db)
-  set(MD5_JPEG_420S_IFAST_OPT 388708217ac46273ca33086b22827ed8)
-
-  set(MD5_JPEG_3x2_FLOAT_PROG_SSE 343e3f8caf8af5986ebaf0bdc13b5c71)
-  set(MD5_PPM_3x2_FLOAT_SSE 1a75f36e5904d6fc3a85a43da9ad89bb)
-  set(MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT 9bca803d2042bd1eb03819e2bf92b3e5)
-  set(MD5_PPM_3x2_FLOAT_NO_FP_CONTRACT f6bfab038438ed8f5522fbd33595dcdc)
-  set(MD5_JPEG_3x2_FLOAT_PROG_FP_CONTRACT
-    ${MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT})
-  set(MD5_PPM_3x2_FLOAT_FP_CONTRACT 0e917a34193ef976b679a6b069b1be26)
-  set(MD5_JPEG_3x2_FLOAT_PROG_387 1657664a410e0822c924b54f6f65e6e9)
-  set(MD5_PPM_3x2_FLOAT_387 cb0a1f027f3d2917c902b5640214e025)
-  set(MD5_JPEG_3x2_FLOAT_PROG_MSVC 7999ce9cd0ee9b6c7043b7351ab7639d)
-  set(MD5_PPM_3x2_FLOAT_MSVC 28cdc448a6b75e97892f0e0f8d4b21f3)
-
-  set(MD5_JPEG_3x2_IFAST_PROG 1ee5d2c1a77f2da495f993c8c7cceca5)
-  set(MD5_PPM_3x2_IFAST fd283664b3b49127984af0a7f118fccd)
-  set(MD5_JPEG_420_ISLOW_ARI e986fb0a637a8d833d96e8a6d6d84ea1)
-  set(MD5_JPEG_444_ISLOW_PROGARI 0a8f1c8f66e113c3cf635df0a475a617)
-  set(MD5_PPM_420M_IFAST_ARI 57251da28a35b46eecb7177d82d10e0e)
-  set(MD5_JPEG_420_ISLOW 9a68f56bc76e466aa7e52f415d0f4a5f)
-  set(MD5_PPM_420M_ISLOW_2_1 9f9de8c0612f8d06869b960b05abf9c9)
-  set(MD5_PPM_420M_ISLOW_15_8 b6875bc070720b899566cc06459b63b7)
-  set(MD5_PPM_420M_ISLOW_13_8 bc3452573c8152f6ae552939ee19f82f)
-  set(MD5_PPM_420M_ISLOW_11_8 d8cc73c0aaacd4556569b59437ba00a5)
-  set(MD5_PPM_420M_ISLOW_9_8 d25e61bc7eac0002f5b393aa223747b6)
-  set(MD5_PPM_420M_ISLOW_7_8 ddb564b7c74a09494016d6cd7502a946)
-  set(MD5_PPM_420M_ISLOW_3_4 8ed8e68808c3fbc4ea764fc9d2968646)
-  set(MD5_PPM_420M_ISLOW_5_8 a3363274999da2366a024efae6d16c9b)
-  set(MD5_PPM_420M_ISLOW_1_2 e692a315cea26b988c8e8b29a5dbcd81)
-  set(MD5_PPM_420M_ISLOW_3_8 79eca9175652ced755155c90e785a996)
-  set(MD5_PPM_420M_ISLOW_1_4 79cd778f8bf1a117690052cacdd54eca)
-  set(MD5_PPM_420M_ISLOW_1_8 391b3d4aca640c8567d6f8745eb2142f)
-  set(MD5_BMP_420_ISLOW_256 4980185e3776e89bd931736e1cddeee6)
-  set(MD5_BMP_420_ISLOW_565 bf9d13e16c4923b92e1faa604d7922cb)
-  set(MD5_BMP_420_ISLOW_565D 6bde71526acc44bcff76f696df8638d2)
-  set(MD5_BMP_420M_ISLOW_565 8dc0185245353cfa32ad97027342216f)
-  set(MD5_BMP_420M_ISLOW_565D ce034037d212bc403330df6f915c161b)
-  set(MD5_PPM_420_ISLOW_SKIP15_31 c4c65c1e43d7275cd50328a61e6534f0)
-  set(MD5_PPM_420_ISLOW_ARI_SKIP16_139 087c6b123db16ac00cb88c5b590bb74a)
-  set(MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71 26eb36ccc7d1f0cb80cdabb0ac8b5d99)
-  set(MD5_PPM_420_ISLOW_ARI_CROP53x53_4_4 886c6775af22370257122f8b16207e6d)
-  set(MD5_PPM_444_ISLOW_SKIP1_6 5606f86874cf26b8fcee1117a0a436a6)
-  set(MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13 db87dc7ce26bcdc7a6b56239ce2b9d6c)
-  set(MD5_PPM_444_ISLOW_ARI_CROP37x37_0_0 cb57b32bd6d03e35432362f7bf184b6d)
-  set(MD5_JPEG_CROP b4197f377e621c4e9b1d20471432610d)
-endif()
-
 if(WITH_JAVA)
   add_test(TJUnitTest
     ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
@@ -860,6 +824,10 @@ if(WITH_JAVA)
     ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
       -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
       TJUnitTest -yuv -noyuvpad)
+  add_test(TJUnitTest-lossless
+    ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
+      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
+      TJUnitTest -lossless)
   add_test(TJUnitTest-bi
     ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
       -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
@@ -872,6 +840,22 @@ if(WITH_JAVA)
     ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
       -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
       TJUnitTest -bi -yuv -noyuvpad)
+  add_test(TJUnitTest-bi-lossless
+    ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
+      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
+      TJUnitTest -bi -lossless)
+  add_test(TJUnitTest12
+    ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
+      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
+      TJUnitTest -precision 12)
+  add_test(TJUnitTest12-lossless
+    ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
+      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
+      TJUnitTest -precision 12 -lossless)
+  add_test(TJUnitTest16-lossless
+    ${Java_JAVA_EXECUTABLE} ${JAVAARGS} -cp java/turbojpeg.jar
+      -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR}/${OBJDIR}
+      TJUnitTest -precision 16)
 endif()
 
 set(TEST_LIBTYPES "")
@@ -890,22 +874,22 @@ if(CMAKE_CROSSCOMPILING)
 endif()
 
 # The output of the floating point DCT/IDCT algorithms differs depending on the
-# type of floating point math used, so the FLOATTEST CMake variable must be
-# set in order to tell the testing system which floating point results it
-# should expect:
+# type of floating point math used, so the FLOATTEST8 and FLOATTEST12 CMake
+# variables must be set in order to tell the testing system which floating
+# point results it should expect:
 #
 # sse = validate against the expected results from the libjpeg-turbo SSE SIMD
 #       extensions
 # no-fp-contract = validate against the expected results from the C code when
 #                  floating point expression contraction is disabled (the
-#                  default with Clang, with GCC when building for platforms
-#                  that lack fused multiply-add [FMA] instructions, or when
-#                  passing -ffp-contract=off to the compiler)
+#                  default with Clang 13 and earlier, when building for
+#                  platforms that lack fused multiply-add [FMA] instructions,
+#                  or when passing -ffp-contract=off to GCC or Clang)
 # fp-contract = validate against the expected results from the C code when
 #               floating point expression contraction is enabled (the default
-#               with GCC when building for platforms that have fused multiply-
-#               add [FMA] instructions or when passing -ffp-contract=fast to
-#               the compiler)
+#               with Clang 14 and later, with GCC when building for platforms
+#               that have fused multiply-add [FMA] instructions, or when
+#               passing -ffp-contract=fast to GCC or -ffp-contract=on to Clang)
 # 387 = validate against the expected results from the C code when the 387 FPU
 #       is being used for floating point math (which is generally the default
 #       with x86 compilers)
@@ -914,43 +898,83 @@ endif()
 
 if(CPU_TYPE STREQUAL "x86_64" OR CPU_TYPE STREQUAL "i386")
   if(WITH_SIMD)
-    set(DEFAULT_FLOATTEST sse)
+    set(DEFAULT_FLOATTEST8 sse)
   elseif(CPU_TYPE STREQUAL "x86_64")
-    set(DEFAULT_FLOATTEST no-fp-contract)
-  # else we can't really set an intelligent default for i386.  The appropriate
-  # value could be no-fp-contract, fp-contract, 387, or msvc, depending on the
-  # compiler and compiler options.  We leave it to the user to set FLOATTEST
-  # manually.
+    set(DEFAULT_FLOATTEST8 no-fp-contract)
   endif()
-else()
-  if((CPU_TYPE STREQUAL "powerpc" OR CPU_TYPE STREQUAL "arm64") AND
-    NOT CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT MSVC)
-    set(DEFAULT_FLOATTEST fp-contract)
-  else()
-    set(DEFAULT_FLOATTEST no-fp-contract)
+elseif(CPU_TYPE STREQUAL "powerpc" OR CPU_TYPE STREQUAL "arm64")
+  if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+    if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 14.0.0 OR
+      CMAKE_C_COMPILER_VERSION VERSION_GREATER 14.0.0)
+      set(DEFAULT_FLOATTEST8 fp-contract)
+    else()
+      set(DEFAULT_FLOATTEST8 no-fp-contract)
+    endif()
+  elseif(CMAKE_COMPILER_IS_GNUCC)
+    set(DEFAULT_FLOATTEST8 fp-contract)
   endif()
+# else we can't really set an intelligent default for FLOATTEST8.  The
+# appropriate value could be no-fp-contract, fp-contract, 387, or msvc,
+# depending on the compiler and compiler options.  We leave it to the user to
+# set FLOATTEST8 manually.
 endif()
 
-# This causes FLOATTEST to reset to the default value if WITH_SIMD has
+# This causes FLOATTEST8 to reset to the default value if WITH_SIMD has
 # changed.
 if(DEFINED WITH_SIMD_INT AND NOT WITH_SIMD EQUAL WITH_SIMD_INT)
-  set(FORCE_FLOATTEST "FORCE")
+  set(FORCE_FLOATTEST8 "FORCE")
 endif()
 set(WITH_SIMD_INT ${WITH_SIMD} CACHE INTERNAL "")
-set(FLOATTEST ${DEFAULT_FLOATTEST} CACHE STRING
-  "The type of floating point math used by the floating point DCT/IDCT algorithms.  This tells the testing system which numerical results it should expect from those tests.  [sse = libjpeg-turbo x86/x86-64 SIMD extensions, no-fp-contract = generic FPU with floating point expression contraction disabled, fp-contract = generic FPU with floating point expression contraction enabled, 387 = 387 FPU, msvc = 32-bit Visual Studio] (default = ${DEFAULT_FLOATTEST})"
-  ${FORCE_FLOATTEST})
-message(STATUS "FLOATTEST = ${FLOATTEST}")
-
-if(FLOATTEST)
-  string(TOUPPER ${FLOATTEST} FLOATTEST_UC)
-  string(REGEX REPLACE "-" "_" FLOATTEST_UC ${FLOATTEST_UC})
-  string(TOLOWER ${FLOATTEST} FLOATTEST)
-  if(NOT FLOATTEST STREQUAL "sse" AND
-    NOT FLOATTEST STREQUAL "no-fp-contract" AND
-    NOT FLOATTEST STREQUAL "fp-contract" AND NOT FLOATTEST STREQUAL "387" AND
-    NOT FLOATTEST STREQUAL "msvc")
-    message(FATAL_ERROR "\"${FLOATTEST}\" is not a valid value for FLOATTEST.")
+set(FLOATTEST8 ${DEFAULT_FLOATTEST8} CACHE STRING
+  "The type of floating point math used by the 8-bit-per-sample floating point DCT/IDCT algorithms.  This tells the testing system which numerical results it should expect from those tests.  [sse = libjpeg-turbo x86/x86-64 SIMD extensions, no-fp-contract = generic FPU with floating point expression contraction disabled, fp-contract = generic FPU with floating point expression contraction enabled, 387 = 387 FPU, msvc = 32-bit Visual Studio] (default = ${DEFAULT_FLOATTEST8})"
+  ${FORCE_FLOATTEST8})
+message(STATUS "FLOATTEST8 = ${FLOATTEST8}")
+
+if(FLOATTEST8)
+  string(TOUPPER ${FLOATTEST8} FLOATTEST8_UC)
+  string(REGEX REPLACE "-" "_" FLOATTEST8_UC ${FLOATTEST8_UC})
+  string(TOLOWER ${FLOATTEST8} FLOATTEST8)
+  if(NOT FLOATTEST8 STREQUAL "sse" AND
+    NOT FLOATTEST8 STREQUAL "no-fp-contract" AND
+    NOT FLOATTEST8 STREQUAL "fp-contract" AND NOT FLOATTEST8 STREQUAL "387" AND
+    NOT FLOATTEST8 STREQUAL "msvc")
+    message(FATAL_ERROR "\"${FLOATTEST8}\" is not a valid value for FLOATTEST8.")
+  endif()
+endif()
+
+if(CPU_TYPE STREQUAL "x86_64")
+  set(DEFAULT_FLOATTEST12 no-fp-contract)
+elseif(CPU_TYPE STREQUAL "powerpc" OR CPU_TYPE STREQUAL "arm64")
+  if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+    if(CMAKE_C_COMPILER_VERSION VERSION_EQUAL 14.0.0 OR
+      CMAKE_C_COMPILER_VERSION VERSION_GREATER 14.0.0)
+      set(DEFAULT_FLOATTEST12 fp-contract)
+    else()
+      set(DEFAULT_FLOATTEST12 no-fp-contract)
+    endif()
+  elseif(CMAKE_COMPILER_IS_GNUCC)
+    set(DEFAULT_FLOATTEST12 fp-contract)
+  endif()
+# else we can't really set an intelligent default for FLOATTEST12.  The
+# appropriate value could be no-fp-contract, fp-contract, or something else,
+# depending on the compiler and compiler options.  We leave it to the user to
+# set FLOATTEST12 manually.
+endif()
+
+set(FLOATTEST12 ${DEFAULT_FLOATTEST12} CACHE STRING
+  "The type of floating point math used by the 12-bit-per-sample floating point DCT/IDCT algorithms.  This tells the testing system which numerical results it should expect from those tests.  [sse = libjpeg-turbo x86/x86-64 SIMD extensions, no-fp-contract = generic FPU with floating point expression contraction disabled, fp-contract = generic FPU with floating point expression contraction enabled, 387 = 387 FPU, msvc = 32-bit Visual Studio] (default = ${DEFAULT_FLOATTEST12})")
+message(STATUS "FLOATTEST12 = ${FLOATTEST12}")
+
+if(FLOATTEST12)
+  string(TOUPPER ${FLOATTEST12} FLOATTEST12_UC)
+  string(REGEX REPLACE "-" "_" FLOATTEST12_UC ${FLOATTEST12_UC})
+  string(TOLOWER ${FLOATTEST12} FLOATTEST12)
+  if(NOT FLOATTEST12 STREQUAL "sse" AND
+    NOT FLOATTEST12 STREQUAL "no-fp-contract" AND
+    NOT FLOATTEST12 STREQUAL "fp-contract" AND
+    NOT FLOATTEST12 STREQUAL "387" AND
+    NOT FLOATTEST12 STREQUAL "msvc")
+    message(FATAL_ERROR "\"${FLOATTEST12}\" is not a valid value for FLOATTEST12.")
   endif()
 endif()
 
@@ -969,85 +993,143 @@ foreach(libtype ${TEST_LIBTYPES})
       ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -yuv -alloc)
     add_test(tjunittest-${libtype}-yuv-nopad
       ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -yuv -noyuvpad)
+    add_test(tjunittest-${libtype}-lossless
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -lossless)
+    add_test(tjunittest-${libtype}-lossless-alloc
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -lossless -alloc)
     add_test(tjunittest-${libtype}-bmp
       ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -bmp)
+    add_test(tjunittest12-${libtype}
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 12)
+    add_test(tjunittest12-${libtype}-alloc
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 12
+        -alloc)
+    add_test(tjunittest12-${libtype}-lossless
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 12
+        -lossless)
+    add_test(tjunittest12-${libtype}-lossless-alloc
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 12
+        -lossless -alloc)
+    add_test(tjunittest12-${libtype}-bmp
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 12 -bmp)
+    add_test(tjunittest16-${libtype}-lossless
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 16)
+    add_test(tjunittest16-${libtype}-lossless-alloc
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 16
+        -alloc)
+    add_test(tjunittest16-${libtype}-bmp
+      ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -precision 16 -bmp)
+
+    foreach(sample_bits 8 12)
+
+      if(sample_bits EQUAL 12)
+        set(tjbench tjbench12)
+        set(testout testout12${suffix})
+
+        set(MD5_PPM_GRAY_TILE 2f799249148b1a9d0e61fa4408f6c397)
+        set(MD5_PPM_420_8x8_TILE b25684e1af37be504ee3fd137757353f)
+        set(MD5_PPM_420_16x16_TILE 2c1af444a63d19167eb3f4c1fa7f1b67)
+        set(MD5_PPM_420_32x32_TILE cce091fe18688f39bc0b5ba29238e1e2)
+        set(MD5_PPM_420_64x64_TILE f770ec8f710a014606dee662bc88606d)
+        set(MD5_PPM_420_128x128_TILE a841bc82e9eda34cbdefe53f808b339c)
+        set(MD5_PPM_420M_8x8_TILE 9de845a8d805affb9ae3a7b2712eaa46)
+        set(MD5_PPM_420M_TILE 455d273be0e229b9c8aabb16481bce5b)
+        set(MD5_PPM_422_8x8_TILE 5e9f784a98a7eae2789ea1458ed43748)
+        set(MD5_PPM_422_16x16_TILE c8df65a792d371a30c8fb7352f320314)
+        set(MD5_PPM_422_32x32_TILE b523b630237e3305a5c4d353ff4ee19b)
+        set(MD5_PPM_422_64x64_TILE eb30bdd20337079745b039e24e613bfd)
+        set(MD5_PPM_422_128x128_TILE 7997458635973b004da46863e2da55ea)
+        set(MD5_PPM_422M_8x8_TILE f8443fffd32cce7681dd36010ce43c07)
+        set(MD5_PPM_422M_TILE a0d45368343a63ca2c8ee87cc4ef9ded)
+        set(MD5_PPM_444_TILE 2f571a032e4dbc8ef40f75219d336b0b)
+      else()
+        set(tjbench tjbench)
+        set(testout testout${suffix})
+
+        set(MD5_PPM_GRAY_TILE 2c3b567086e6ca0c5e6d34ad8d6f6fe8)
+        set(MD5_PPM_420_8x8_TILE efca1bdf0226df01777137778cf986ec)
+        set(MD5_PPM_420_16x16_TILE 8c92c7453870d9e11c6d1dec3a8c9101)
+        set(MD5_PPM_420_32x32_TILE 3f7651872a95e469d1c7115f1b11ecef)
+        set(MD5_PPM_420_64x64_TILE f64c71af03fdea12363b62f1a3096aab)
+        set(MD5_PPM_420_128x128_TILE 5a5ef57517558c671bf5e75793588d69)
+        set(MD5_PPM_420M_8x8_TILE 66bd869b315a32a00fef1a025661ce72)
+        set(MD5_PPM_420M_TILE bf9ec2ab4875abb2efcce8f876fe2c2a)
+        set(MD5_PPM_422_8x8_TILE c300553ce1b3b90fd414ec96b62fe988)
+        set(MD5_PPM_422_16x16_TILE 6559ddb1191f5b2d3eb41081b254c4e0)
+        set(MD5_PPM_422_32x32_TILE 58691797f4584c4c5ed5965a6bb9aec0)
+        set(MD5_PPM_422_64x64_TILE 7f9e34942ae46af7b784f459ec133f5e)
+        set(MD5_PPM_422_128x128_TILE 6afcb77580d85dd3eacb04b3c2bc7710)
+        set(MD5_PPM_422M_8x8_TILE 55df1f96bcfb631aedeb940cf3f011f5)
+        set(MD5_PPM_422M_TILE 6502031018c2d2f69bc6353347f8df4d)
+        set(MD5_PPM_444_TILE 87bd58005eec73f0f313c8e38d0d793c)
+      endif()
 
-    set(MD5_PPM_GRAY_TILE 89d3ca21213d9d864b50b4e4e7de4ca6)
-    set(MD5_PPM_420_8x8_TILE 847fceab15c5b7b911cb986cf0f71de3)
-    set(MD5_PPM_420_16x16_TILE ca45552a93687e078f7137cc4126a7b0)
-    set(MD5_PPM_420_32x32_TILE d8676f1d6b68df358353bba9844f4a00)
-    set(MD5_PPM_420_64x64_TILE 4e4c1a3d7ea4bace4f868bcbe83b7050)
-    set(MD5_PPM_420_128x128_TILE f24c3429c52265832beab9df72a0ceae)
-    set(MD5_PPM_420M_8x8_TILE bc25320e1f4c31ce2e610e43e9fd173c)
-    set(MD5_PPM_420M_TILE 75ffdf14602258c5c189522af57fa605)
-    set(MD5_PPM_422_8x8_TILE d83dacd9fc73b0a6f10c09acad64eb1e)
-    set(MD5_PPM_422_16x16_TILE 35077fb610d72dd743b1eb0cbcfe10fb)
-    set(MD5_PPM_422_32x32_TILE e6902ed8a449ecc0f0d6f2bf945f65f7)
-    set(MD5_PPM_422_64x64_TILE 2b4502a8f316cedbde1da7bce3d2231e)
-    set(MD5_PPM_422_128x128_TILE f0b5617d578f5e13c8eee215d64d4877)
-    set(MD5_PPM_422M_8x8_TILE 828941d7f41cd6283abd6beffb7fd51d)
-    set(MD5_PPM_422M_TILE e877ae1324c4a280b95376f7f018172f)
-    set(MD5_PPM_444_TILE 7964e41e67cfb8d0a587c0aa4798f9c3)
-
-    # Test compressing from/decompressing to an arbitrary subregion of a larger
-    # image buffer
-    add_test(tjbench-${libtype}-tile-cp
-      ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm
-        testout_tile.ppm)
-    add_test(tjbench-${libtype}-tile
-      ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} testout_tile.ppm 95
-        -rgb -quiet -tile -benchtime 0.01 -warmup 0)
-    set_tests_properties(tjbench-${libtype}-tile
-      PROPERTIES DEPENDS tjbench-${libtype}-tile-cp)
-
-    foreach(tile 8 16 32 64 128)
-      add_test(tjbench-${libtype}-tile-gray-${tile}x${tile}-cmp
-        ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_GRAY_TILE}
-          testout_tile_GRAY_Q95_${tile}x${tile}.ppm)
-      foreach(subsamp 420 422)
-        add_test(tjbench-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp
-          ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
-            ${MD5_PPM_${subsamp}_${tile}x${tile}_TILE}
-            testout_tile_${subsamp}_Q95_${tile}x${tile}.ppm)
-      endforeach()
-      add_test(tjbench-${libtype}-tile-444-${tile}x${tile}-cmp
-        ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_444_TILE}
-          testout_tile_444_Q95_${tile}x${tile}.ppm)
-      foreach(subsamp gray 420 422 444)
-        set_tests_properties(tjbench-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp
-          PROPERTIES DEPENDS tjbench-${libtype}-tile)
+      # Test compressing from/decompressing to an arbitrary subregion of a larger
+      # image buffer
+      add_test(${tjbench}-${libtype}-tile-cp
+        ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm
+          ${testout}_tile.ppm)
+      add_test(${tjbench}-${libtype}-tile
+        ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} ${testout}_tile.ppm
+          95 -precision ${sample_bits} -rgb -quiet -tile -benchtime 0.01
+          -warmup 0)
+      set_tests_properties(${tjbench}-${libtype}-tile
+        PROPERTIES DEPENDS ${tjbench}-${libtype}-tile-cp)
+
+      foreach(tile 8 16 32 64 128)
+        add_test(${tjbench}-${libtype}-tile-gray-${tile}x${tile}-cmp
+          ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_GRAY_TILE}
+            ${testout}_tile_GRAY_Q95_${tile}x${tile}.ppm)
+        foreach(subsamp 420 422)
+          add_test(${tjbench}-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp
+            ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
+              ${MD5_PPM_${subsamp}_${tile}x${tile}_TILE}
+              ${testout}_tile_${subsamp}_Q95_${tile}x${tile}.ppm)
+        endforeach()
+        add_test(${tjbench}-${libtype}-tile-444-${tile}x${tile}-cmp
+          ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_444_TILE}
+            ${testout}_tile_444_Q95_${tile}x${tile}.ppm)
+        foreach(subsamp gray 420 422 444)
+          set_tests_properties(
+            ${tjbench}-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp
+            PROPERTIES DEPENDS ${tjbench}-${libtype}-tile)
+        endforeach()
       endforeach()
-    endforeach()
 
-    add_test(tjbench-${libtype}-tilem-cp
-      ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm
-        testout_tilem.ppm)
-    add_test(tjbench-${libtype}-tilem
-      ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} testout_tilem.ppm 95
-        -rgb -fastupsample -quiet -tile -benchtime 0.01 -warmup 0)
-    set_tests_properties(tjbench-${libtype}-tilem
-      PROPERTIES DEPENDS tjbench-${libtype}-tilem-cp)
-
-    add_test(tjbench-${libtype}-tile-420m-8x8-cmp
-      ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_420M_8x8_TILE}
-        testout_tilem_420_Q95_8x8.ppm)
-    add_test(tjbench-${libtype}-tile-422m-8x8-cmp
-      ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_422M_8x8_TILE}
-        testout_tilem_422_Q95_8x8.ppm)
-    foreach(tile 16 32 64 128)
-      foreach(subsamp 420 422)
-        add_test(tjbench-${libtype}-tile-${subsamp}m-${tile}x${tile}-cmp
-          ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
-            ${MD5_PPM_${subsamp}M_TILE}
-            testout_tilem_${subsamp}_Q95_${tile}x${tile}.ppm)
+      add_test(${tjbench}-${libtype}-tilem-cp
+        ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm
+          ${testout}_tilem.ppm)
+      add_test(${tjbench}-${libtype}-tilem
+        ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} ${testout}_tilem.ppm
+          95 -precision ${sample_bits} -rgb -fastupsample -quiet -tile
+          -benchtime 0.01 -warmup 0)
+      set_tests_properties(${tjbench}-${libtype}-tilem
+        PROPERTIES DEPENDS ${tjbench}-${libtype}-tilem-cp)
+
+      add_test(${tjbench}-${libtype}-tile-420m-8x8-cmp
+        ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_420M_8x8_TILE}
+          ${testout}_tilem_420_Q95_8x8.ppm)
+      add_test(${tjbench}-${libtype}-tile-422m-8x8-cmp
+        ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_422M_8x8_TILE}
+          ${testout}_tilem_422_Q95_8x8.ppm)
+      foreach(tile 16 32 64 128)
+        foreach(subsamp 420 422)
+          add_test(${tjbench}-${libtype}-tile-${subsamp}m-${tile}x${tile}-cmp
+            ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
+              ${MD5_PPM_${subsamp}M_TILE}
+              ${testout}_tilem_${subsamp}_Q95_${tile}x${tile}.ppm)
+        endforeach()
       endforeach()
-    endforeach()
-    foreach(tile 8 16 32 64 128)
-      foreach(subsamp 420 422)
-        set_tests_properties(tjbench-${libtype}-tile-${subsamp}m-${tile}x${tile}-cmp
-          PROPERTIES DEPENDS tjbench-${libtype}-tilem)
+      foreach(tile 8 16 32 64 128)
+        foreach(subsamp 420 422)
+          set_tests_properties(
+            ${tjbench}-${libtype}-tile-${subsamp}m-${tile}x${tile}-cmp
+            PROPERTIES DEPENDS ${tjbench}-${libtype}-tilem)
+        endforeach()
       endforeach()
+
     endforeach()
+
   endif()
 
   # These tests are carefully crafted to provide full coverage of as many of
@@ -1055,8 +1137,17 @@ foreach(libtype ${TEST_LIBTYPES})
   # SIMD-accelerated ones.)
 
   macro(add_bittest PROG NAME ARGS OUTFILE INFILE MD5SUM)
+    if(${PROG} STREQUAL "cjpeg16")
+      set(ACTUAL_ARGS "${ARGS};-precision;16")
+    elseif(${PROG} STREQUAL "cjpeg12")
+      set(ACTUAL_ARGS "${ARGS};-precision;12")
+    else()
+      set(ACTUAL_ARGS ${ARGS})
+    endif()
+    string(REGEX REPLACE "16" "" ACTUAL_PROG ${PROG})
+    string(REGEX REPLACE "12" "" ACTUAL_PROG ${ACTUAL_PROG})
     add_test(${PROG}-${libtype}-${NAME}
-      ${CMAKE_CROSSCOMPILING_EMULATOR} ${PROG}${suffix} ${ARGS}
+      ${CMAKE_CROSSCOMPILING_EMULATOR} ${ACTUAL_PROG}${suffix} ${ACTUAL_ARGS}
         -outfile ${OUTFILE} ${INFILE})
     add_test(${PROG}-${libtype}-${NAME}-cmp
       ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5SUM} ${OUTFILE})
@@ -1069,296 +1160,515 @@ foreach(libtype ${TEST_LIBTYPES})
     endif()
   endmacro()
 
-  # CC: null  SAMP: fullsize  FDCT: islow  ENT: huff
-  add_bittest(cjpeg rgb-islow "-rgb;-dct;int;-icc;${TESTIMAGES}/test1.icc"
-    testout_rgb_islow.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_RGB_ISLOW})
-
-  # CC: null  SAMP: fullsize  IDCT: islow  ENT: huff
-  add_bittest(djpeg rgb-islow "-dct;int;-ppm;-icc;testout_rgb_islow.icc"
-    testout_rgb_islow.ppm testout_rgb_islow.jpg
-    ${MD5_PPM_RGB_ISLOW} cjpeg-${libtype}-rgb-islow)
-
-  add_test(djpeg-${libtype}-rgb-islow-icc-cmp
-    ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
-      b06a39d730129122e85c1363ed1bbc9e testout_rgb_islow.icc)
-  set_tests_properties(djpeg-${libtype}-rgb-islow-icc-cmp PROPERTIES
-    DEPENDS djpeg-${libtype}-rgb-islow)
-
-  add_bittest(jpegtran icc "-copy;all;-icc;${TESTIMAGES}/test2.icc"
-    testout_rgb_islow2.jpg testout_rgb_islow.jpg
-    ${MD5_JPEG_RGB_ISLOW2} cjpeg-${libtype}-rgb-islow)
-
-  if(NOT WITH_12BIT)
-    # CC: RGB->RGB565  SAMP: fullsize  IDCT: islow  ENT: huff
-    add_bittest(djpeg rgb-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
-      testout_rgb_islow_565.bmp testout_rgb_islow.jpg
-      ${MD5_BMP_RGB_ISLOW_565} cjpeg-${libtype}-rgb-islow)
-
-    # CC: RGB->RGB565 (dithered)  SAMP: fullsize  IDCT: islow  ENT: huff
-    add_bittest(djpeg rgb-islow-565D "-dct;int;-rgb565;-bmp"
-      testout_rgb_islow_565D.bmp testout_rgb_islow.jpg
-      ${MD5_BMP_RGB_ISLOW_565D} cjpeg-${libtype}-rgb-islow)
-  endif()
+  set(MD5_JPEG_LOSSLESS fe99437df4e9976fe5e841969242b208)
+  set(MD5_PPM_LOSSLESS 01d9642a2b8723fefebbe9cb074ccd02)
+
+  # Lossless (all arguments other than -lossless and -restart should have no
+  # effect)
+  add_bittest(cjpeg16 lossless
+    "-lossless;4;-restart;1;-quality;1;-grayscale;-optimize;-dct;float;-smooth;100;-baseline;-qslots;1,0,0;-sample;1x2,3x4,2x1"
+    testout16_lossless.jpg ${TESTIMAGES}/testorig.ppm
+    ${MD5_JPEG_LOSSLESS})
+  add_bittest(djpeg16 lossless
+    "-fast;-scale;1/8;-dct;float;-dither;none;-nosmooth;-onepass"
+    testout16_lossless.ppm testout16_lossless.jpg
+    ${MD5_PPM_LOSSLESS} cjpeg16-${libtype}-lossless)
+
+  foreach(sample_bits 8 12)
+
+    if(sample_bits EQUAL 12)
+      set(cjpeg cjpeg12)
+      set(djpeg djpeg12)
+      set(jpegtran jpegtran12)
+      set(testout testout12${suffix})
+
+      set(TESTORIG testorig12.jpg)
+      set(MD5_JPEG_RGB_ISLOW 9d7369207c520d37f2c1cbfcb82b2964)
+      set(MD5_JPEG_RGB_ISLOW2 a00bd20d8ae49684640ef7177d2e0b64)
+      set(MD5_PPM_RGB_ISLOW f3301d2219783b8b3d942b7239fa50c0)
+      set(MD5_JPEG_422_IFAST_OPT 7322e3bd2f127f7de4b40d4480ce60e4)
+      set(MD5_PPM_422_IFAST 79807fa552899e66a04708f533e16950)
+      set(MD5_JPEG_440_ISLOW e25c1912e38367be505a89c410c1c2d2)
+      set(MD5_PPM_440_ISLOW e7d2e26288870cfcb30f3114ad01e380)
+      set(MD5_PPM_422M_IFAST 07737bfe8a7c1c87aaa393a0098d16b0)
+      set(MD5_JPEG_420_IFAST_Q100_PROG 9447cef4803d9b0f74bcf333cc710a29)
+      set(MD5_PPM_420_Q100_IFAST 1b3730122709f53d007255e8dfd3305e)
+      set(MD5_PPM_420M_Q100_IFAST 980a1a3c5bf9510022869d30b7d26566)
+      set(MD5_JPEG_GRAY_ISLOW 235c90707b16e2e069f37c888b2636d9)
+      set(MD5_PPM_GRAY_ISLOW 7213c10af507ad467da5578ca5ee1fca)
+      set(MD5_PPM_GRAY_ISLOW_RGB e96ee81c30a6ed422d466338bd3de65d)
+      set(MD5_JPEG_420S_IFAST_OPT 7af8e60be4d9c227ec63ac9b6630855e)
+
+      set(MD5_JPEG_3x2_FLOAT_PROG_SSE a8c17daf77b457725ec929e215b603f8)
+      set(MD5_PPM_3x2_FLOAT_SSE 42876ab9e5c2f76a87d08db5fbd57956)
+      set(MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT
+        a8c17daf77b457725ec929e215b603f8)
+      set(MD5_PPM_3x2_FLOAT_NO_FP_CONTRACT ${MD5_PPM_3x2_FLOAT_SSE})
+      set(MD5_JPEG_3x2_FLOAT_PROG_FP_CONTRACT
+        ${MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT})
+      if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+        set(MD5_PPM_3x2_FLOAT_FP_CONTRACT 2da9de6ae869e88b8372de815d366b03)
+      else()
+        set(MD5_PPM_3x2_FLOAT_FP_CONTRACT ${MD5_PPM_3x2_FLOAT_SSE})
+      endif()
+      set(MD5_JPEG_3x2_FLOAT_PROG_387 bc6dbbefac2872f6b9d6c4a0ae60c3c0)
+      set(MD5_PPM_3x2_FLOAT_387 bcc5723c61560463ac60f772e742d092)
+      set(MD5_JPEG_3x2_FLOAT_PROG_MSVC e27840755870fa849872e58aa0cd1400)
+      set(MD5_PPM_3x2_FLOAT_MSVC 6c2880b83bb1aa41dfe330e7a9768690)
+
+      set(MD5_JPEG_3x2_IFAST_PROG 1396cc2b7185cfe943d408c9d305339e)
+      set(MD5_PPM_3x2_IFAST 3975985ef6eeb0a2cdc58daa651ccc00)
+      set(MD5_PPM_420M_ISLOW_2_1 4ca6be2a6f326ff9eaab63e70a8259c0)
+      set(MD5_PPM_420M_ISLOW_15_8 12aa9f9534c1b3d7ba047322226365eb)
+      set(MD5_PPM_420M_ISLOW_13_8 f7e22817c7b25e1393e4ec101e9d4e96)
+      set(MD5_PPM_420M_ISLOW_11_8 800a16f9f4dc9b293197bfe11be10a82)
+      set(MD5_PPM_420M_ISLOW_9_8 06b7a92a9bc69f4dc36ec40f1937d55c)
+      set(MD5_PPM_420M_ISLOW_7_8 3ec444a14a4ab4eab88ffc49c48eca43)
+      set(MD5_PPM_420M_ISLOW_3_4 3e726b7ea872445b19437d1c1d4f0d93)
+      set(MD5_PPM_420M_ISLOW_5_8 a8a771abdc94301d20ffac119b2caccd)
+      set(MD5_PPM_420M_ISLOW_1_2 b419124dd5568b085787234866102866)
+      set(MD5_PPM_420M_ISLOW_3_8 343d19015531b7bbe746124127244fa8)
+      set(MD5_PPM_420M_ISLOW_1_4 35fd59d866e44659edfa3c18db2a3edb)
+      set(MD5_PPM_420M_ISLOW_1_8 ccaed48ac0aedefda5d4abe4013f4ad7)
+      set(MD5_JPEG_LOSSLESS 8473501f5bb7c826524472c858bf4fcd)
+      set(MD5_PPM_LOSSLESS 1da3fb2620e5a4e258e0fcb891bc67e8)
+      set(MD5_PPM_420_ISLOW_SKIP15_31 86664cd9dc956536409e44e244d20a97)
+      set(MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71
+        452a21656115a163029cfba5c04fa76a)
+      set(MD5_PPM_444_ISLOW_SKIP1_6 ef63901f71ef7a75cd78253fc0914f84)
+      set(MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13
+        15b173fb5872d9575572fbcc1b05956f)
+      set(MD5_JPEG_CROP cdb35ff4b4519392690ea040c56ea99c)
+
+      set(MD5_JPEG_EXAMPLE_COMPRESS 5e502da0c3c0f957a58c536f31e973dc)
+      set(MD5_PPM_EXAMPLE_DECOMPRESS 2ff0e8505ee6e0ffaeb24037d5650b57)
+    else()
+      set(cjpeg cjpeg)
+      set(djpeg djpeg)
+      set(jpegtran jpegtran)
+      set(testout testout${suffix})
+
+      set(TESTORIG testorig.jpg)
+      set(MD5_JPEG_RGB_ISLOW 1d44a406f61da743b5fd31c0a9abdca3)
+      set(MD5_JPEG_RGB_ISLOW2 31d121e57b6c2934c890a7fc7763bcd4)
+      set(MD5_PPM_RGB_ISLOW 00a257f5393fef8821f2b88ac7421291)
+      set(MD5_BMP_RGB_ISLOW_565 f07d2e75073e4bb10f6c6f4d36e2e3be)
+      set(MD5_BMP_RGB_ISLOW_565D 4cfa0928ef3e6bb626d7728c924cfda4)
+      set(MD5_JPEG_422_IFAST_OPT 2540287b79d913f91665e660303ab2c8)
+      set(MD5_PPM_422_IFAST 35bd6b3f833bad23de82acea847129fa)
+      set(MD5_JPEG_440_ISLOW 538bc02bd4b4658fd85de6ece6cbeda6)
+      set(MD5_PPM_440_ISLOW 11e7eab7ef7ef3276934bb7e7b6bb377)
+      set(MD5_PPM_422M_IFAST 8dbc65323d62cca7c91ba02dd1cfa81d)
+      set(MD5_BMP_422M_IFAST_565 3294bd4d9a1f2b3d08ea6020d0db7065)
+      set(MD5_BMP_422M_IFAST_565D da98c9c7b6039511be4a79a878a9abc1)
+      set(MD5_JPEG_420_IFAST_Q100_PROG 0ba15f9dab81a703505f835f9dbbac6d)
+      set(MD5_PPM_420_Q100_IFAST 5a732542015c278ff43635e473a8a294)
+      set(MD5_PPM_420M_Q100_IFAST ff692ee9323a3b424894862557c092f1)
+      set(MD5_JPEG_GRAY_ISLOW 72b51f894b8f4a10b3ee3066770aa38d)
+      set(MD5_PPM_GRAY_ISLOW 8d3596c56eace32f205deccc229aa5ed)
+      set(MD5_PPM_GRAY_ISLOW_RGB 116424ac07b79e5e801f00508eab48ec)
+      set(MD5_BMP_GRAY_ISLOW_565 12f78118e56a2f48b966f792fedf23cc)
+      set(MD5_BMP_GRAY_ISLOW_565D bdbbd616441a24354c98553df5dc82db)
+      set(MD5_JPEG_420S_IFAST_OPT 388708217ac46273ca33086b22827ed8)
+
+      set(MD5_JPEG_3x2_FLOAT_PROG_SSE 343e3f8caf8af5986ebaf0bdc13b5c71)
+      set(MD5_PPM_3x2_FLOAT_SSE 1a75f36e5904d6fc3a85a43da9ad89bb)
+      set(MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT
+        9bca803d2042bd1eb03819e2bf92b3e5)
+      set(MD5_PPM_3x2_FLOAT_NO_FP_CONTRACT f6bfab038438ed8f5522fbd33595dcdc)
+      set(MD5_JPEG_3x2_FLOAT_PROG_FP_CONTRACT
+        ${MD5_JPEG_3x2_FLOAT_PROG_NO_FP_CONTRACT})
+      if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+        set(MD5_PPM_3x2_FLOAT_FP_CONTRACT ${MD5_PPM_3x2_FLOAT_NO_FP_CONTRACT})
+      else()
+        set(MD5_PPM_3x2_FLOAT_FP_CONTRACT 0e917a34193ef976b679a6b069b1be26)
+      endif()
+      set(MD5_JPEG_3x2_FLOAT_PROG_387 1657664a410e0822c924b54f6f65e6e9)
+      set(MD5_PPM_3x2_FLOAT_387 cb0a1f027f3d2917c902b5640214e025)
+      set(MD5_JPEG_3x2_FLOAT_PROG_MSVC 7999ce9cd0ee9b6c7043b7351ab7639d)
+      set(MD5_PPM_3x2_FLOAT_MSVC 28cdc448a6b75e97892f0e0f8d4b21f3)
+
+      set(MD5_JPEG_3x2_IFAST_PROG 1ee5d2c1a77f2da495f993c8c7cceca5)
+      set(MD5_PPM_3x2_IFAST fd283664b3b49127984af0a7f118fccd)
+      set(MD5_JPEG_420_ISLOW_ARI e986fb0a637a8d833d96e8a6d6d84ea1)
+      set(MD5_JPEG_444_ISLOW_PROGARI 0a8f1c8f66e113c3cf635df0a475a617)
+      set(MD5_PPM_420M_IFAST_ARI 57251da28a35b46eecb7177d82d10e0e)
+      set(MD5_JPEG_420_ISLOW 9a68f56bc76e466aa7e52f415d0f4a5f)
+      set(MD5_PPM_420M_ISLOW_2_1 9f9de8c0612f8d06869b960b05abf9c9)
+      set(MD5_PPM_420M_ISLOW_15_8 b6875bc070720b899566cc06459b63b7)
+      set(MD5_PPM_420M_ISLOW_13_8 bc3452573c8152f6ae552939ee19f82f)
+      set(MD5_PPM_420M_ISLOW_11_8 d8cc73c0aaacd4556569b59437ba00a5)
+      set(MD5_PPM_420M_ISLOW_9_8 d25e61bc7eac0002f5b393aa223747b6)
+      set(MD5_PPM_420M_ISLOW_7_8 ddb564b7c74a09494016d6cd7502a946)
+      set(MD5_PPM_420M_ISLOW_3_4 8ed8e68808c3fbc4ea764fc9d2968646)
+      set(MD5_PPM_420M_ISLOW_5_8 a3363274999da2366a024efae6d16c9b)
+      set(MD5_PPM_420M_ISLOW_1_2 e692a315cea26b988c8e8b29a5dbcd81)
+      set(MD5_PPM_420M_ISLOW_3_8 79eca9175652ced755155c90e785a996)
+      set(MD5_PPM_420M_ISLOW_1_4 79cd778f8bf1a117690052cacdd54eca)
+      set(MD5_PPM_420M_ISLOW_1_8 391b3d4aca640c8567d6f8745eb2142f)
+      set(MD5_BMP_420_ISLOW_256 4980185e3776e89bd931736e1cddeee6)
+      set(MD5_BMP_420_ISLOW_565 bf9d13e16c4923b92e1faa604d7922cb)
+      set(MD5_BMP_420_ISLOW_565D 6bde71526acc44bcff76f696df8638d2)
+      set(MD5_BMP_420M_ISLOW_565 8dc0185245353cfa32ad97027342216f)
+      set(MD5_BMP_420M_ISLOW_565D ce034037d212bc403330df6f915c161b)
+      set(MD5_JPEG_LOSSLESS fc777b82d42d835ae1282ba1ee87c209)
+      set(MD5_PPM_LOSSLESS 64072f1dbdc5b3a187777788604971a5)
+      set(MD5_PPM_420_ISLOW_SKIP15_31 c4c65c1e43d7275cd50328a61e6534f0)
+      set(MD5_PPM_420_ISLOW_ARI_SKIP16_139 087c6b123db16ac00cb88c5b590bb74a)
+      set(MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71
+        26eb36ccc7d1f0cb80cdabb0ac8b5d99)
+      set(MD5_PPM_420_ISLOW_ARI_CROP53x53_4_4 886c6775af22370257122f8b16207e6d)
+      set(MD5_PPM_444_ISLOW_SKIP1_6 5606f86874cf26b8fcee1117a0a436a6)
+      set(MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13
+        db87dc7ce26bcdc7a6b56239ce2b9d6c)
+      set(MD5_PPM_444_ISLOW_ARI_CROP37x37_0_0 cb57b32bd6d03e35432362f7bf184b6d)
+      set(MD5_JPEG_CROP b4197f377e621c4e9b1d20471432610d)
+
+      set(MD5_JPEG_EXAMPLE_COMPRESS 95d4d72e2ef127332654c2599afb47bf)
+      set(MD5_PPM_EXAMPLE_DECOMPRESS 6fdde7301575bfd711e295b969b6b3de)
+    endif()
 
-  # CC: RGB->YCC  SAMP: fullsize/h2v1  FDCT: ifast  ENT: 2-pass huff
-  add_bittest(cjpeg 422-ifast-opt "-sample;2x1;-dct;fast;-opt"
-    testout_422_ifast_opt.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_422_IFAST_OPT})
-
-  # CC: YCC->RGB  SAMP: fullsize/h2v1 fancy  IDCT: ifast  ENT: huff
-  add_bittest(djpeg 422-ifast "-dct;fast"
-    testout_422_ifast.ppm testout_422_ifast_opt.jpg
-    ${MD5_PPM_422_IFAST} cjpeg-${libtype}-422-ifast-opt)
-
-  # CC: RGB->YCC  SAMP: fullsize/h1v2  FDCT: islow  ENT: huff
-  add_bittest(cjpeg 440-islow "-sample;1x2;-dct;int"
-    testout_440_islow.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_440_ISLOW})
-
-  # CC: YCC->RGB  SAMP: fullsize/h1v2 fancy  IDCT: islow  ENT: huff
-  add_bittest(djpeg 440-islow "-dct;int"
-    testout_440_islow.ppm testout_440_islow.jpg
-    ${MD5_PPM_440_ISLOW} cjpeg-${libtype}-440-islow)
-
-  # CC: YCC->RGB  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
-  add_bittest(djpeg 422m-ifast "-dct;fast;-nosmooth"
-    testout_422m_ifast.ppm testout_422_ifast_opt.jpg
-    ${MD5_PPM_422M_IFAST} cjpeg-${libtype}-422-ifast-opt)
-
-  if(NOT WITH_12BIT)
-    # CC: YCC->RGB565  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
-    add_bittest(djpeg 422m-ifast-565
-      "-dct;int;-nosmooth;-rgb565;-dither;none;-bmp"
-      testout_422m_ifast_565.bmp testout_422_ifast_opt.jpg
-      ${MD5_BMP_422M_IFAST_565} cjpeg-${libtype}-422-ifast-opt)
-
-    # CC: YCC->RGB565 (dithered)  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
-    add_bittest(djpeg 422m-ifast-565D "-dct;int;-nosmooth;-rgb565;-bmp"
-      testout_422m_ifast_565D.bmp testout_422_ifast_opt.jpg
-      ${MD5_BMP_422M_IFAST_565D} cjpeg-${libtype}-422-ifast-opt)
-  endif()
+    # CC: null  SAMP: fullsize  FDCT: islow  ENT: huff
+    add_bittest(${cjpeg} rgb-islow "-rgb;-dct;int;-icc;${TESTIMAGES}/test1.icc"
+      ${testout}_rgb_islow.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_RGB_ISLOW})
+
+    # CC: null  SAMP: fullsize  IDCT: islow  ENT: huff
+    add_bittest(${djpeg} rgb-islow
+      "-dct;int;-ppm;-icc;${testout}_rgb_islow.icc"
+      ${testout}_rgb_islow.ppm ${testout}_rgb_islow.jpg
+      ${MD5_PPM_RGB_ISLOW} ${cjpeg}-${libtype}-rgb-islow)
+
+    add_test(${djpeg}-${libtype}-rgb-islow-icc-cmp
+      ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP}
+        b06a39d730129122e85c1363ed1bbc9e ${testout}_rgb_islow.icc)
+    set_tests_properties(${djpeg}-${libtype}-rgb-islow-icc-cmp PROPERTIES
+      DEPENDS ${djpeg}-${libtype}-rgb-islow)
+
+    add_bittest(${jpegtran} icc "-copy;all;-icc;${TESTIMAGES}/test2.icc"
+      ${testout}_rgb_islow2.jpg ${testout}_rgb_islow.jpg
+      ${MD5_JPEG_RGB_ISLOW2} ${cjpeg}-${libtype}-rgb-islow)
+
+    if(sample_bits EQUAL 8)
+      # CC: RGB->RGB565  SAMP: fullsize  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} rgb-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
+        ${testout}_rgb_islow_565.bmp ${testout}_rgb_islow.jpg
+        ${MD5_BMP_RGB_ISLOW_565} ${cjpeg}-${libtype}-rgb-islow)
+
+      # CC: RGB->RGB565 (dithered)  SAMP: fullsize  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} rgb-islow-565D "-dct;int;-rgb565;-bmp"
+        ${testout}_rgb_islow_565D.bmp ${testout}_rgb_islow.jpg
+        ${MD5_BMP_RGB_ISLOW_565D} ${cjpeg}-${libtype}-rgb-islow)
+    endif()
 
-  # CC: RGB->YCC  SAMP: fullsize/h2v2  FDCT: ifast  ENT: prog huff
-  add_bittest(cjpeg 420-q100-ifast-prog
-    "-sample;2x2;-quality;100;-dct;fast;-scans;${TESTIMAGES}/test.scan"
-    testout_420_q100_ifast_prog.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_420_IFAST_Q100_PROG})
-
-  # CC: YCC->RGB  SAMP: fullsize/h2v2 fancy  IDCT: ifast  ENT: prog huff
-  add_bittest(djpeg 420-q100-ifast-prog "-dct;fast"
-    testout_420_q100_ifast.ppm testout_420_q100_ifast_prog.jpg
-    ${MD5_PPM_420_Q100_IFAST} cjpeg-${libtype}-420-q100-ifast-prog)
-
-  # CC: YCC->RGB  SAMP: h2v2 merged  IDCT: ifast  ENT: prog huff
-  add_bittest(djpeg 420m-q100-ifast-prog "-dct;fast;-nosmooth"
-    testout_420m_q100_ifast.ppm testout_420_q100_ifast_prog.jpg
-    ${MD5_PPM_420M_Q100_IFAST} cjpeg-${libtype}-420-q100-ifast-prog)
-
-  # CC: RGB->Gray  SAMP: fullsize  FDCT: islow  ENT: huff
-  add_bittest(cjpeg gray-islow "-gray;-dct;int"
-    testout_gray_islow.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_GRAY_ISLOW})
-
-  # CC: Gray->Gray  SAMP: fullsize  IDCT: islow  ENT: huff
-  add_bittest(djpeg gray-islow "-dct;int"
-    testout_gray_islow.ppm testout_gray_islow.jpg
-    ${MD5_PPM_GRAY_ISLOW} cjpeg-${libtype}-gray-islow)
-
-  # CC: Gray->RGB  SAMP: fullsize  IDCT: islow  ENT: huff
-  add_bittest(djpeg gray-islow-rgb "-dct;int;-rgb"
-    testout_gray_islow_rgb.ppm testout_gray_islow.jpg
-    ${MD5_PPM_GRAY_ISLOW_RGB} cjpeg-${libtype}-gray-islow)
-
-  if(NOT WITH_12BIT)
-    # CC: Gray->RGB565  SAMP: fullsize  IDCT: islow  ENT: huff
-    add_bittest(djpeg gray-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
-      testout_gray_islow_565.bmp testout_gray_islow.jpg
-      ${MD5_BMP_GRAY_ISLOW_565} cjpeg-${libtype}-gray-islow)
-
-    # CC: Gray->RGB565 (dithered)  SAMP: fullsize  IDCT: islow  ENT: huff
-    add_bittest(djpeg gray-islow-565D "-dct;int;-rgb565;-bmp"
-      testout_gray_islow_565D.bmp testout_gray_islow.jpg
-      ${MD5_BMP_GRAY_ISLOW_565D} cjpeg-${libtype}-gray-islow)
-  endif()
+    # CC: RGB->YCC  SAMP: fullsize/h2v1  FDCT: ifast  ENT: 2-pass huff
+    add_bittest(${cjpeg} 422-ifast-opt "-sample;2x1;-dct;fast;-opt"
+      ${testout}_422_ifast_opt.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_422_IFAST_OPT})
+
+    # CC: YCC->RGB  SAMP: fullsize/h2v1 fancy  IDCT: ifast  ENT: huff
+    add_bittest(${djpeg} 422-ifast "-dct;fast"
+      ${testout}_422_ifast.ppm ${testout}_422_ifast_opt.jpg
+      ${MD5_PPM_422_IFAST} ${cjpeg}-${libtype}-422-ifast-opt)
+
+    # CC: RGB->YCC  SAMP: fullsize/h1v2  FDCT: islow  ENT: huff
+    add_bittest(${cjpeg} 440-islow "-sample;1x2;-dct;int"
+      ${testout}_440_islow.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_440_ISLOW})
+
+    # CC: YCC->RGB  SAMP: fullsize/h1v2 fancy  IDCT: islow  ENT: huff
+    add_bittest(${djpeg} 440-islow "-dct;int"
+      ${testout}_440_islow.ppm ${testout}_440_islow.jpg
+      ${MD5_PPM_440_ISLOW} ${cjpeg}-${libtype}-440-islow)
+
+    # CC: YCC->RGB  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
+    add_bittest(${djpeg} 422m-ifast "-dct;fast;-nosmooth"
+      ${testout}_422m_ifast.ppm ${testout}_422_ifast_opt.jpg
+      ${MD5_PPM_422M_IFAST} ${cjpeg}-${libtype}-422-ifast-opt)
+
+    if(sample_bits EQUAL 8)
+      # CC: YCC->RGB565  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
+      add_bittest(${djpeg} 422m-ifast-565
+        "-dct;int;-nosmooth;-rgb565;-dither;none;-bmp"
+        ${testout}_422m_ifast_565.bmp ${testout}_422_ifast_opt.jpg
+        ${MD5_BMP_422M_IFAST_565} ${cjpeg}-${libtype}-422-ifast-opt)
+
+      # CC: YCC->RGB565 (dithered)  SAMP: h2v1 merged  IDCT: ifast  ENT: huff
+      add_bittest(${djpeg} 422m-ifast-565D "-dct;int;-nosmooth;-rgb565;-bmp"
+        ${testout}_422m_ifast_565D.bmp ${testout}_422_ifast_opt.jpg
+        ${MD5_BMP_422M_IFAST_565D} ${cjpeg}-${libtype}-422-ifast-opt)
+    endif()
 
-  # CC: RGB->YCC  SAMP: fullsize smooth/h2v2 smooth  FDCT: islow
-  # ENT: 2-pass huff
-  add_bittest(cjpeg 420s-ifast-opt "-sample;2x2;-smooth;1;-dct;int;-opt"
-    testout_420s_ifast_opt.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_420S_IFAST_OPT})
-
-  if(FLOATTEST)
-    # CC: RGB->YCC  SAMP: fullsize/int  FDCT: float  ENT: prog huff
-    add_bittest(cjpeg 3x2-float-prog "-sample;3x2;-dct;float;-prog"
-      testout_3x2_float_prog.jpg ${TESTIMAGES}/testorig.ppm
-      ${MD5_JPEG_3x2_FLOAT_PROG_${FLOATTEST_UC}})
-
-    # CC: YCC->RGB  SAMP: fullsize/int  IDCT: float  ENT: prog huff
-    add_bittest(djpeg 3x2-float-prog "-dct;float"
-      testout_3x2_float.ppm testout_3x2_float_prog.jpg
-      ${MD5_PPM_3x2_FLOAT_${FLOATTEST_UC}} cjpeg-${libtype}-3x2-float-prog)
-  endif()
+    # CC: RGB->YCC  SAMP: fullsize/h2v2  FDCT: ifast  ENT: prog huff
+    add_bittest(${cjpeg} 420-q100-ifast-prog
+      "-sample;2x2;-quality;100;-dct;fast;-scans;${TESTIMAGES}/test.scan"
+      ${testout}_420_q100_ifast_prog.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_420_IFAST_Q100_PROG})
+
+    # CC: YCC->RGB  SAMP: fullsize/h2v2 fancy  IDCT: ifast  ENT: prog huff
+    add_bittest(${djpeg} 420-q100-ifast-prog "-dct;fast"
+      ${testout}_420_q100_ifast.ppm ${testout}_420_q100_ifast_prog.jpg
+      ${MD5_PPM_420_Q100_IFAST} ${cjpeg}-${libtype}-420-q100-ifast-prog)
+
+    # CC: YCC->RGB  SAMP: h2v2 merged  IDCT: ifast  ENT: prog huff
+    add_bittest(${djpeg} 420m-q100-ifast-prog "-dct;fast;-nosmooth"
+      ${testout}_420m_q100_ifast.ppm ${testout}_420_q100_ifast_prog.jpg
+      ${MD5_PPM_420M_Q100_IFAST} ${cjpeg}-${libtype}-420-q100-ifast-prog)
+
+    # CC: RGB->Gray  SAMP: fullsize  FDCT: islow  ENT: huff
+    add_bittest(${cjpeg} gray-islow "-gray;-dct;int"
+      ${testout}_gray_islow.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_GRAY_ISLOW})
+
+    # CC: Gray->Gray  SAMP: fullsize  IDCT: islow  ENT: huff
+    add_bittest(${djpeg} gray-islow "-dct;int"
+      ${testout}_gray_islow.ppm ${testout}_gray_islow.jpg
+      ${MD5_PPM_GRAY_ISLOW} ${cjpeg}-${libtype}-gray-islow)
+
+    # CC: Gray->RGB  SAMP: fullsize  IDCT: islow  ENT: huff
+    add_bittest(${djpeg} gray-islow-rgb "-dct;int;-rgb"
+      ${testout}_gray_islow_rgb.ppm ${testout}_gray_islow.jpg
+      ${MD5_PPM_GRAY_ISLOW_RGB} ${cjpeg}-${libtype}-gray-islow)
+
+    if(sample_bits EQUAL 8)
+      # CC: Gray->RGB565  SAMP: fullsize  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} gray-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
+        ${testout}_gray_islow_565.bmp ${testout}_gray_islow.jpg
+        ${MD5_BMP_GRAY_ISLOW_565} ${cjpeg}-${libtype}-gray-islow)
+
+      # CC: Gray->RGB565 (dithered)  SAMP: fullsize  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} gray-islow-565D "-dct;int;-rgb565;-bmp"
+        ${testout}_gray_islow_565D.bmp ${testout}_gray_islow.jpg
+        ${MD5_BMP_GRAY_ISLOW_565D} ${cjpeg}-${libtype}-gray-islow)
+    endif()
+
+    # CC: RGB->YCC  SAMP: fullsize smooth/h2v2 smooth  FDCT: islow
+    # ENT: 2-pass huff
+    add_bittest(${cjpeg} 420s-ifast-opt "-sample;2x2;-smooth;1;-dct;int;-opt"
+      ${testout}_420s_ifast_opt.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_420S_IFAST_OPT})
+
+    if(FLOATTEST${sample_bits})
+      # CC: RGB->YCC  SAMP: fullsize/int  FDCT: float  ENT: prog huff
+      add_bittest(${cjpeg} 3x2-float-prog "-sample;3x2;-dct;float;-prog"
+        ${testout}_3x2_float_prog.jpg ${TESTIMAGES}/testorig.ppm
+        ${MD5_JPEG_3x2_FLOAT_PROG_${FLOATTEST${sample_bits}_UC}})
+
+      # CC: YCC->RGB  SAMP: fullsize/int  IDCT: float  ENT: prog huff
+      add_bittest(${djpeg} 3x2-float-prog "-dct;float"
+        ${testout}_3x2_float.ppm ${testout}_3x2_float_prog.jpg
+        ${MD5_PPM_3x2_FLOAT_${FLOATTEST${sample_bits}_UC}}
+        ${cjpeg}-${libtype}-3x2-float-prog)
+    endif()
 
     # CC: RGB->YCC  SAMP: fullsize/int  FDCT: ifast  ENT: prog huff
-  add_bittest(cjpeg 3x2-ifast-prog "-sample;3x2;-dct;fast;-prog"
-    testout_3x2_ifast_prog.jpg ${TESTIMAGES}/testorig.ppm
-    ${MD5_JPEG_3x2_IFAST_PROG})
-
-  # CC: YCC->RGB  SAMP: fullsize/int  IDCT: ifast  ENT: prog huff
-  add_bittest(djpeg 3x2-ifast-prog "-dct;fast"
-    testout_3x2_ifast.ppm testout_3x2_ifast_prog.jpg
-    ${MD5_PPM_3x2_IFAST} cjpeg-${libtype}-3x2-ifast-prog)
-
-  if(WITH_ARITH_ENC)
-    # CC: YCC->RGB  SAMP: fullsize/h2v2  FDCT: islow  ENT: arith
-    add_bittest(cjpeg 420-islow-ari "-dct;int;-arithmetic"
-      testout_420_islow_ari.jpg ${TESTIMAGES}/testorig.ppm
-      ${MD5_JPEG_420_ISLOW_ARI})
-
-    add_bittest(jpegtran 420-islow-ari "-arithmetic"
-      testout_420_islow_ari2.jpg ${TESTIMAGES}/testimgint.jpg
-      ${MD5_JPEG_420_ISLOW_ARI})
-
-    # CC: YCC->RGB  SAMP: fullsize  FDCT: islow  ENT: prog arith
-    add_bittest(cjpeg 444-islow-progari
-      "-sample;1x1;-dct;int;-prog;-arithmetic"
-      testout_444_islow_progari.jpg ${TESTIMAGES}/testorig.ppm
-      ${MD5_JPEG_444_ISLOW_PROGARI})
-  endif()
+    add_bittest(${cjpeg} 3x2-ifast-prog "-sample;3x2;-dct;fast;-prog"
+      ${testout}_3x2_ifast_prog.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_3x2_IFAST_PROG})
+
+    # CC: YCC->RGB  SAMP: fullsize/int  IDCT: ifast  ENT: prog huff
+    add_bittest(${djpeg} 3x2-ifast-prog "-dct;fast"
+      ${testout}_3x2_ifast.ppm ${testout}_3x2_ifast_prog.jpg
+      ${MD5_PPM_3x2_IFAST} ${cjpeg}-${libtype}-3x2-ifast-prog)
+
+    if(WITH_ARITH_ENC AND sample_bits EQUAL 8)
+      # CC: YCC->RGB  SAMP: fullsize/h2v2  FDCT: islow  ENT: arith
+      add_bittest(${cjpeg} 420-islow-ari "-dct;int;-arithmetic"
+        ${testout}_420_islow_ari.jpg ${TESTIMAGES}/testorig.ppm
+        ${MD5_JPEG_420_ISLOW_ARI})
+
+      add_bittest(${jpegtran} 420-islow-ari "-arithmetic"
+        ${testout}_420_islow_ari2.jpg ${TESTIMAGES}/testimgint.jpg
+        ${MD5_JPEG_420_ISLOW_ARI})
+
+      # CC: YCC->RGB  SAMP: fullsize  FDCT: islow  ENT: prog arith
+      add_bittest(${cjpeg} 444-islow-progari
+        "-sample;1x1;-dct;int;-prog;-arithmetic"
+        ${testout}_444_islow_progari.jpg ${TESTIMAGES}/testorig.ppm
+        ${MD5_JPEG_444_ISLOW_PROGARI})
+    endif()
 
-  if(WITH_ARITH_DEC)
-    # CC: RGB->YCC  SAMP: h2v2 merged  IDCT: ifast  ENT: arith
-    add_bittest(djpeg 420m-ifast-ari "-fast;-skip;1,20;-ppm"
-      testout_420m_ifast_ari.ppm ${TESTIMAGES}/testimgari.jpg
-      ${MD5_PPM_420M_IFAST_ARI})
+    if(WITH_ARITH_DEC AND sample_bits EQUAL 8)
+      # CC: RGB->YCC  SAMP: h2v2 merged  IDCT: ifast  ENT: arith
+      add_bittest(${djpeg} 420m-ifast-ari "-fast;-skip;1,20;-ppm"
+        ${testout}_420m_ifast_ari.ppm ${TESTIMAGES}/testimgari.jpg
+        ${MD5_PPM_420M_IFAST_ARI})
 
-    add_bittest(jpegtran 420-islow ""
-      testout_420_islow.jpg ${TESTIMAGES}/testimgari.jpg
-      ${MD5_JPEG_420_ISLOW})
-  endif()
+      add_bittest(${jpegtran} 420-islow ""
+        ${testout}_420_islow.jpg ${TESTIMAGES}/testimgari.jpg
+        ${MD5_JPEG_420_ISLOW})
+    endif()
 
-  # 2/1--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 16x16 islow  ENT: huff
-  # 15/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 15x15 islow  ENT: huff
-  # 13/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 13x13 islow  ENT: huff
-  # 11/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 11x11 islow  ENT: huff
-  # 9/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 9x9 islow  ENT: huff
-  # 7/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 7x7 islow/14x14 islow
-  #         ENT: huff
-  # 3/4--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 6x6 islow/12x12 islow
-  #         ENT: huff
-  # 5/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 5x5 islow/10x10 islow
-  #         ENT: huff
-  # 1/2--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 4x4 islow/8x8 islow
-  #         ENT: huff
-  # 3/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 3x3 islow/6x6 islow
-  #         ENT: huff
-  # 1/4--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 2x2 islow/4x4 islow
-  #         ENT: huff
-  # 1/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 1x1 islow/2x2 islow
-  #         ENT: huff
-  foreach(scale 2_1 15_8 13_8 11_8 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8)
-    string(REGEX REPLACE "_" "/" scalearg ${scale})
-    add_bittest(djpeg 420m-islow-${scale}
-      "-dct;int;-scale;${scalearg};-nosmooth;-ppm"
-      testout_420m_islow_${scale}.ppm ${TESTIMAGES}/${TESTORIG}
-      ${MD5_PPM_420M_ISLOW_${scale}})
-  endforeach()
+    # 2/1--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 16x16 islow  ENT: huff
+    # 15/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 15x15 islow  ENT: huff
+    # 13/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 13x13 islow  ENT: huff
+    # 11/8--  CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 11x11 islow  ENT: huff
+    # 9/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 9x9 islow  ENT: huff
+    # 7/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 7x7 islow/14x14 islow
+    #         ENT: huff
+    # 3/4--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 6x6 islow/12x12 islow
+    #         ENT: huff
+    # 5/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 5x5 islow/10x10 islow
+    #         ENT: huff
+    # 1/2--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 4x4 islow/8x8 islow
+    #         ENT: huff
+    # 3/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 3x3 islow/6x6 islow
+    #         ENT: huff
+    # 1/4--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 2x2 islow/4x4 islow
+    #         ENT: huff
+    # 1/8--   CC: YCC->RGB  SAMP: h2v2 merged  IDCT: 1x1 islow/2x2 islow
+    #         ENT: huff
+    foreach(scale 2_1 15_8 13_8 11_8 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8)
+      string(REGEX REPLACE "_" "/" scalearg ${scale})
+      add_bittest(${djpeg} 420m-islow-${scale}
+        "-dct;int;-scale;${scalearg};-nosmooth;-ppm"
+        ${testout}_420m_islow_${scale}.ppm ${TESTIMAGES}/${TESTORIG}
+        ${MD5_PPM_420M_ISLOW_${scale}})
+    endforeach()
 
-  if(NOT WITH_12BIT)
-    # CC: YCC->RGB (dithered)  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
-    add_bittest(djpeg 420-islow-256 "-dct;int;-colors;256;-bmp"
-      testout_420_islow_256.bmp ${TESTIMAGES}/${TESTORIG}
-      ${MD5_BMP_420_ISLOW_256})
-
-    # CC: YCC->RGB565  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
-    add_bittest(djpeg 420-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
-      testout_420_islow_565.bmp ${TESTIMAGES}/${TESTORIG}
-      ${MD5_BMP_420_ISLOW_565})
-
-    # CC: YCC->RGB565 (dithered)  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
-    add_bittest(djpeg 420-islow-565D "-dct;int;-rgb565;-bmp"
-      testout_420_islow_565D.bmp ${TESTIMAGES}/${TESTORIG}
-      ${MD5_BMP_420_ISLOW_565D})
-
-    # CC: YCC->RGB565  SAMP: h2v2 merged  IDCT: islow  ENT: huff
-    add_bittest(djpeg 420m-islow-565
-      "-dct;int;-nosmooth;-rgb565;-dither;none;-bmp"
-      testout_420m_islow_565.bmp ${TESTIMAGES}/${TESTORIG}
-      ${MD5_BMP_420M_ISLOW_565})
-
-    # CC: YCC->RGB565 (dithered)  SAMP: h2v2 merged  IDCT: islow  ENT: huff
-    add_bittest(djpeg 420m-islow-565D "-dct;int;-nosmooth;-rgb565;-bmp"
-      testout_420m_islow_565D.bmp ${TESTIMAGES}/${TESTORIG}
-      ${MD5_BMP_420M_ISLOW_565D})
-  endif()
+    if(sample_bits EQUAL 8)
+      # CC: YCC->RGB (dithered)  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} 420-islow-256 "-dct;int;-colors;256;-bmp"
+        ${testout}_420_islow_256.bmp ${TESTIMAGES}/${TESTORIG}
+        ${MD5_BMP_420_ISLOW_256})
+
+      # CC: YCC->RGB565  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} 420-islow-565 "-dct;int;-rgb565;-dither;none;-bmp"
+        ${testout}_420_islow_565.bmp ${TESTIMAGES}/${TESTORIG}
+        ${MD5_BMP_420_ISLOW_565})
+
+      # CC: YCC->RGB565 (dithered)  SAMP: h2v2 fancy  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} 420-islow-565D "-dct;int;-rgb565;-bmp"
+        ${testout}_420_islow_565D.bmp ${TESTIMAGES}/${TESTORIG}
+        ${MD5_BMP_420_ISLOW_565D})
+
+      # CC: YCC->RGB565  SAMP: h2v2 merged  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} 420m-islow-565
+        "-dct;int;-nosmooth;-rgb565;-dither;none;-bmp"
+        ${testout}_420m_islow_565.bmp ${TESTIMAGES}/${TESTORIG}
+        ${MD5_BMP_420M_ISLOW_565})
+
+      # CC: YCC->RGB565 (dithered)  SAMP: h2v2 merged  IDCT: islow  ENT: huff
+      add_bittest(${djpeg} 420m-islow-565D "-dct;int;-nosmooth;-rgb565;-bmp"
+        ${testout}_420m_islow_565D.bmp ${TESTIMAGES}/${TESTORIG}
+        ${MD5_BMP_420M_ISLOW_565D})
+    endif()
 
-  # Partial decode tests.  These tests are designed to cover all of the
-  # possible code paths in jpeg_skip_scanlines().
+    # Lossless (all arguments other than -lossless and -restart should have no
+    # effect)
+    add_bittest(${cjpeg} lossless
+      "-lossless;4;-restart;1;-quality;1;-grayscale;-optimize;-dct;float;-smooth;100;-baseline;-qslots;1,0,0;-sample;1x2,3x4,2x1"
+      ${testout}_lossless.jpg ${TESTIMAGES}/testorig.ppm
+      ${MD5_JPEG_LOSSLESS})
+    add_bittest(${djpeg} lossless
+      "-fast;-scale;1/8;-dct;float;-dither;none;-nosmooth;-onepass"
+      ${testout}_lossless.ppm ${testout}_lossless.jpg
+      ${MD5_PPM_LOSSLESS} ${cjpeg}-${libtype}-lossless)
+
+    # Partial decode tests.  These tests are designed to cover all of the
+    # possible code paths in jpeg_skip_scanlines().
+
+    # Context rows: Yes  Intra-iMCU row: Yes  iMCU row prefetch: No
+    # ENT: huff
+    add_bittest(${djpeg} 420-islow-skip15_31 "-dct;int;-skip;15,31;-ppm"
+      ${testout}_420_islow_skip15,31.ppm ${TESTIMAGES}/${TESTORIG}
+      ${MD5_PPM_420_ISLOW_SKIP15_31})
+
+    # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: Yes
+    # ENT: arith
+    if(WITH_ARITH_DEC AND sample_bits EQUAL 8)
+      add_bittest(${djpeg} 420-islow-ari-skip16_139
+        "-dct;int;-skip;16,139;-ppm"
+        ${testout}_420_islow_ari_skip16,139.ppm ${TESTIMAGES}/testimgari.jpg
+        ${MD5_PPM_420_ISLOW_ARI_SKIP16_139})
+    endif()
 
-  # Context rows: Yes  Intra-iMCU row: Yes  iMCU row prefetch: No   ENT: huff
-  add_bittest(djpeg 420-islow-skip15_31 "-dct;int;-skip;15,31;-ppm"
-    testout_420_islow_skip15,31.ppm ${TESTIMAGES}/${TESTORIG}
-    ${MD5_PPM_420_ISLOW_SKIP15_31})
+    # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No
+    # ENT: prog huff
+    add_test(${cjpeg}-${libtype}-420-islow-prog
+      ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog
+        -precision ${sample_bits} -outfile ${testout}_420_islow_prog.jpg
+        ${TESTIMAGES}/testorig.ppm)
+    add_bittest(${djpeg} 420-islow-prog-crop62x62_71_71
+      "-dct;int;-crop;62x62+71+71;-ppm"
+      ${testout}_420_islow_prog_crop62x62,71,71.ppm
+      ${testout}_420_islow_prog.jpg ${MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71}
+      ${cjpeg}-${libtype}-420-islow-prog)
+
+    # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No
+    # ENT: arith
+    if(WITH_ARITH_DEC AND sample_bits EQUAL 8)
+      add_bittest(${djpeg} 420-islow-ari-crop53x53_4_4
+        "-dct;int;-crop;53x53+4+4;-ppm"
+        ${testout}_420_islow_ari_crop53x53,4,4.ppm ${TESTIMAGES}/testimgari.jpg
+        ${MD5_PPM_420_ISLOW_ARI_CROP53x53_4_4})
+    endif()
 
-  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: Yes  ENT: arith
-  if(WITH_ARITH_DEC)
-    add_bittest(djpeg 420-islow-ari-skip16_139 "-dct;int;-skip;16,139;-ppm"
-      testout_420_islow_ari_skip16,139.ppm ${TESTIMAGES}/testimgari.jpg
-      ${MD5_PPM_420_ISLOW_ARI_SKIP16_139})
-  endif()
+    # Context rows: No   Intra-iMCU row: Yes  ENT: huff
+    add_test(${cjpeg}-${libtype}-444-islow
+      ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -sample 1x1
+        -precision ${sample_bits} -outfile ${testout}_444_islow.jpg
+        ${TESTIMAGES}/testorig.ppm)
+    add_bittest(${djpeg} 444-islow-skip1_6 "-dct;int;-skip;1,6;-ppm"
+      ${testout}_444_islow_skip1,6.ppm ${testout}_444_islow.jpg
+      ${MD5_PPM_444_ISLOW_SKIP1_6} ${cjpeg}-${libtype}-444-islow)
+
+    # Context rows: No   Intra-iMCU row: No   ENT: prog huff
+    add_test(${cjpeg}-${libtype}-444-islow-prog
+      ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog
+        -precision ${sample_bits} -sample 1x1
+        -outfile ${testout}_444_islow_prog.jpg ${TESTIMAGES}/testorig.ppm)
+    add_bittest(${djpeg} 444-islow-prog-crop98x98_13_13
+      "-dct;int;-crop;98x98+13+13;-ppm"
+      ${testout}_444_islow_prog_crop98x98,13,13.ppm
+      ${testout}_444_islow_prog.jpg ${MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13}
+      ${cjpeg}-${libtype}-444-islow-prog)
+
+    # Context rows: No   Intra-iMCU row: No   ENT: arith
+    if(WITH_ARITH_ENC AND sample_bits EQUAL 8)
+      add_test(${cjpeg}-${libtype}-444-islow-ari
+        ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -arithmetic
+          -sample 1x1 -precision ${sample_bits}
+          -outfile ${testout}_444_islow_ari.jpg ${TESTIMAGES}/testorig.ppm)
+      if(WITH_ARITH_DEC)
+        add_bittest(${djpeg} 444-islow-ari-crop37x37_0_0
+          "-dct;int;-crop;37x37+0+0;-ppm"
+          ${testout}_444_islow_ari_crop37x37,0,0.ppm
+          ${testout}_444_islow_ari.jpg ${MD5_PPM_444_ISLOW_ARI_CROP37x37_0_0}
+          ${cjpeg}-${libtype}-444-islow-ari)
+      endif()
+    endif()
 
-  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: prog huff
-  add_test(cjpeg-${libtype}-420-islow-prog
-    ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog
-      -outfile testout_420_islow_prog.jpg ${TESTIMAGES}/testorig.ppm)
-  add_bittest(djpeg 420-islow-prog-crop62x62_71_71
-    "-dct;int;-crop;62x62+71+71;-ppm"
-    testout_420_islow_prog_crop62x62,71,71.ppm testout_420_islow_prog.jpg
-    ${MD5_PPM_420_ISLOW_PROG_CROP62x62_71_71} cjpeg-${libtype}-420-islow-prog)
-
-  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: arith
-  if(WITH_ARITH_DEC)
-    add_bittest(djpeg 420-islow-ari-crop53x53_4_4
-      "-dct;int;-crop;53x53+4+4;-ppm"
-      testout_420_islow_ari_crop53x53,4,4.ppm ${TESTIMAGES}/testimgari.jpg
-      ${MD5_PPM_420_ISLOW_ARI_CROP53x53_4_4})
-  endif()
+    add_bittest(${jpegtran} crop "-crop;120x90+20+50;-transpose;-perfect"
+      ${testout}_crop.jpg ${TESTIMAGES}/${TESTORIG}
+      ${MD5_JPEG_CROP})
 
-  # Context rows: No   Intra-iMCU row: Yes  ENT: huff
-  add_test(cjpeg-${libtype}-444-islow
-    ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -sample 1x1
-      -outfile testout_444_islow.jpg ${TESTIMAGES}/testorig.ppm)
-  add_bittest(djpeg 444-islow-skip1_6 "-dct;int;-skip;1,6;-ppm"
-    testout_444_islow_skip1,6.ppm testout_444_islow.jpg
-    ${MD5_PPM_444_ISLOW_SKIP1_6} cjpeg-${libtype}-444-islow)
-
-  # Context rows: No   Intra-iMCU row: No   ENT: prog huff
-  add_test(cjpeg-${libtype}-444-islow-prog
-    ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog -sample 1x1
-      -outfile testout_444_islow_prog.jpg ${TESTIMAGES}/testorig.ppm)
-  add_bittest(djpeg 444-islow-prog-crop98x98_13_13
-    "-dct;int;-crop;98x98+13+13;-ppm"
-    testout_444_islow_prog_crop98x98,13,13.ppm testout_444_islow_prog.jpg
-    ${MD5_PPM_444_ISLOW_PROG_CROP98x98_13_13} cjpeg-${libtype}-444-islow-prog)
-
-  # Context rows: No   Intra-iMCU row: No   ENT: arith
-  if(WITH_ARITH_ENC)
-    add_test(cjpeg-${libtype}-444-islow-ari
-      ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -arithmetic
-        -sample 1x1 -outfile testout_444_islow_ari.jpg
-        ${TESTIMAGES}/testorig.ppm)
-    if(WITH_ARITH_DEC)
-      add_bittest(djpeg 444-islow-ari-crop37x37_0_0
-        "-dct;int;-crop;37x37+0+0;-ppm"
-        testout_444_islow_ari_crop37x37,0,0.ppm testout_444_islow_ari.jpg
-        ${MD5_PPM_444_ISLOW_ARI_CROP37x37_0_0} cjpeg-${libtype}-444-islow-ari)
+    unset(EXAMPLE_12BIT_ARG)
+    if(sample_bits EQUAL 12)
+      set(EXAMPLE_12BIT_ARG "-precision;12")
     endif()
-  endif()
 
-  add_bittest(jpegtran crop "-crop;120x90+20+50;-transpose;-perfect"
-    testout_crop.jpg ${TESTIMAGES}/${TESTORIG}
-    ${MD5_JPEG_CROP})
+    add_test(example-${sample_bits}bit-${libtype}-compress
+      ${CMAKE_CROSSCOMPILING_EMULATOR} example${suffix} compress -q 95
+        ${EXAMPLE_12BIT_ARG} ${testout}-example.jpg)
+    add_test(example-${sample_bits}bit-${libtype}-compress-cmp
+      ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_JPEG_EXAMPLE_COMPRESS}
+        ${testout}-example.jpg)
+    set_tests_properties(example-${sample_bits}bit-${libtype}-compress-cmp
+      PROPERTIES DEPENDS example-${sample_bits}bit-${libtype}-compress)
+
+    add_test(example-${sample_bits}bit-${libtype}-decompress
+      ${CMAKE_CROSSCOMPILING_EMULATOR} example${suffix} decompress
+        ${EXAMPLE_12BIT_ARG} ${testout}-example.jpg ${testout}-example.ppm)
+    set_tests_properties(example-${sample_bits}bit-${libtype}-decompress
+      PROPERTIES DEPENDS example-${sample_bits}bit-${libtype}-compress)
+    add_test(example-${sample_bits}bit-${libtype}-decompress-cmp
+      ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_EXAMPLE_DECOMPRESS}
+        ${testout}-example.ppm)
+    set_tests_properties(example-${sample_bits}bit-${libtype}-decompress-cmp
+      PROPERTIES DEPENDS example-${sample_bits}bit-${libtype}-decompress)
+
+  endforeach()
 
 endforeach()
 
@@ -1376,56 +1686,21 @@ if(WITH_TURBOJPEG)
   if(WIN32)
     set(BASH bash)
   endif()
-  if(WITH_JAVA)
-    configure_file(tjbenchtest.java.in tjbenchtest.java @ONLY)
-    configure_file(tjexampletest.java.in tjexampletest.java @ONLY)
-    add_custom_target(tjtest
-      COMMAND echo tjbenchtest
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
-      COMMAND echo tjbenchtest -alloc
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -alloc
-      COMMAND echo tjbenchtest -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -yuv
-      COMMAND echo tjbenchtest -yuv -alloc
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -yuv -alloc
-      COMMAND echo tjbenchtest -progressive
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -progressive
-      COMMAND echo tjbenchtest -progressive -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -progressive -yuv
-      COMMAND echo tjexampletest
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest
-      COMMAND echo tjbenchtest.java
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest.java
-      COMMAND echo tjbenchtest.java -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest.java -yuv
-      COMMAND echo tjbenchtest.java -progressive
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest.java -progressive
-      COMMAND echo tjexampletest.java -progressive -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest.java
-        -progressive -yuv
-      COMMAND echo tjexampletest.java
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest.java
-      DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
-        ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest.java
-        ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest)
-  else()
-    add_custom_target(tjtest
-      COMMAND echo tjbenchtest
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
-      COMMAND echo tjbenchtest -alloc
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -alloc
-      COMMAND echo tjbenchtest -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -yuv
-      COMMAND echo tjbenchtest -yuv -alloc
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -yuv -alloc
-      COMMAND echo tjbenchtest -progressive
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -progressive
-      COMMAND echo tjbenchtest -progressive -yuv
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest -progressive -yuv
-      COMMAND echo tjexampletest
-      COMMAND ${BASH} ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest
-      DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest)
-  endif()
+  add_custom_target(tjtest COMMAND ${CMAKE_COMMAND} -DWITH_JAVA=${WITH_JAVA}
+    -DPRECISION=8 -P ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+    DEPENDS ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+      ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
+      ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest)
+  add_custom_target(tjtest12 COMMAND ${CMAKE_COMMAND} -DWITH_JAVA=${WITH_JAVA}
+    -DPRECISION=12 -P ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+    DEPENDS ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+      ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
+      ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest)
+  add_custom_target(tjtest16 COMMAND ${CMAKE_COMMAND} -DWITH_JAVA=${WITH_JAVA}
+    -DPRECISION=16 -P ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+    DEPENDS ${CMAKE_SOURCE_DIR}/cmakescripts/tjbenchtest.cmake
+      ${CMAKE_CURRENT_BINARY_DIR}/tjbenchtest
+      ${CMAKE_CURRENT_BINARY_DIR}/tjexampletest)
 endif()
 
 
@@ -1455,7 +1730,7 @@ if(WITH_TURBOJPEG)
       INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
     if(NOT ENABLE_SHARED)
-      if(MSVC_IDE OR XCODE)
+      if(GENERATOR_IS_MULTI_CONFIG)
         set(DIR "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}")
       else()
         set(DIR ${CMAKE_CURRENT_BINARY_DIR})
@@ -1473,7 +1748,7 @@ if(ENABLE_STATIC)
     INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
     ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
   if(NOT ENABLE_SHARED)
-    if(MSVC_IDE OR XCODE)
+    if(GENERATOR_IS_MULTI_CONFIG)
       set(DIR "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}")
     else()
       set(DIR ${CMAKE_CURRENT_BINARY_DIR})
@@ -1490,7 +1765,7 @@ endif()
 install(TARGETS rdjpgcom wrjpgcom RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
 install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/README.ijg
-  ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/example.txt
+  ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/example.c
   ${CMAKE_CURRENT_SOURCE_DIR}/tjexample.c
   ${CMAKE_CURRENT_SOURCE_DIR}/libjpeg.txt
   ${CMAKE_CURRENT_SOURCE_DIR}/structure.txt
index b0d166e..a466785 100644 (file)
@@ -1,7 +1,303 @@
+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 MCU 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.
+     - Optimized baseline entropy coding (the computation of optimal Huffman
+tables, as opposed to using the default Huffman tables) 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](libjpeg.txt), [usage.txt](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](libjpeg.txt), [usage.txt](usage.txt), and the
+TurboJPEG API documentation for more details.
+
+
+2.1.5.1
+=======
+
+### Significant changes relative to 2.1.5:
+
+1. The SIMD dispatchers in libjpeg-turbo 2.1.4 and prior stored the list of
+supported SIMD instruction sets in a global variable, which caused an innocuous
+race condition whereby the variable could have been initialized multiple times
+if `jpeg_start_*compress()` was called simultaneously in multiple threads.
+libjpeg-turbo 2.1.5 included an undocumented attempt to fix this race condition
+by making the SIMD support variable thread-local.  However, that caused another
+issue whereby, if `jpeg_start_*compress()` was called in one thread and
+`jpeg_read_*()` or `jpeg_write_*()` was called in a second thread, the SIMD
+support variable was never initialized in the second thread.  On x86 systems,
+this led the second thread to incorrectly assume that AVX2 instructions were
+always available, and when it attempted to use those instructions on older x86
+CPUs that do not support them, an illegal instruction error occurred.  The SIMD
+dispatchers now ensure that the SIMD support variable is initialized before
+dispatching based on its value.
+
+
+2.1.5
+=====
+
+### Significant changes relative to 2.1.4:
+
+1. Fixed issues in the build system whereby, when using the Ninja Multi-Config
+CMake generator, a static build of libjpeg-turbo (a build in which
+`ENABLE_SHARED` is `0`) could not be installed, a Windows installer could not
+be built, and the Java regression tests failed.
+
+2. Fixed a regression introduced by 2.0 beta1[15] that caused a buffer overrun
+in the progressive Huffman encoder when attempting to transform a
+specially-crafted malformed 12-bit-per-component JPEG image into a progressive
+12-bit-per-component JPEG image using a 12-bit-per-component build of
+libjpeg-turbo (`-DWITH_12BIT=1`.)  Given that the buffer overrun was fully
+contained within the progressive Huffman encoder structure and did not cause a
+segfault or other user-visible errant behavior, given that the lossless
+transformer (unlike the decompressor) is not generally exposed to arbitrary
+data exploits, and given that 12-bit-per-component builds of libjpeg-turbo are
+uncommon, this issue did not likely pose a security risk.
+
+3. Fixed an issue whereby, when using a 12-bit-per-component build of
+libjpeg-turbo (`-DWITH_12BIT=1`), passing samples with values greater than 4095
+or less than 0 to `jpeg_write_scanlines()` caused a buffer overrun or underrun
+in the RGB-to-YCbCr color converter.
+
+4. Fixed a floating point exception that occurred when attempting to use the
+jpegtran `-drop` and `-trim` options to losslessly transform a
+specially-crafted malformed JPEG image.
+
+5. Fixed an issue in `tjBufSizeYUV2()` whereby it returned a bogus result,
+rather than throwing an error, if the `align` parameter was not a power of 2.
+Fixed a similar issue in `tjCompressFromYUV()` whereby it generated a corrupt
+JPEG image in certain cases, rather than throwing an error, if the `align`
+parameter was not a power of 2.
+
+6. Fixed an issue whereby `tjDecompressToYUV2()`, which is a wrapper for
+`tjDecompressToYUVPlanes()`, used the desired YUV image dimensions rather than
+the actual scaled image dimensions when computing the plane pointers and
+strides to pass to `tjDecompressToYUVPlanes()`.  This caused a buffer overrun
+and subsequent segfault if the desired image dimensions exceeded the scaled
+image dimensions.
+
+7. Fixed an issue whereby, when decompressing a 12-bit-per-component JPEG image
+(`-DWITH_12BIT=1`) using an alpha-enabled output color space such as
+`JCS_EXT_RGBA`, the alpha channel was set to 255 rather than 4095.
+
+8. Fixed an issue whereby the Java version of TJBench did not accept a range of
+quality values.
+
+9. Fixed an issue whereby, when `-progressive` was passed to TJBench, the JPEG
+input image was not transformed into a progressive JPEG image prior to
+decompression.
+
+
 2.1.4
 =====
 
-### Significant changes relative to 2.1.3
+### Significant changes relative to 2.1.3:
 
 1. Fixed a regression introduced in 2.1.3 that caused build failures with
 Visual Studio 2010.
@@ -36,7 +332,7 @@ virtual array access") under certain circumstances.
 2.1.3
 =====
 
-### Significant changes relative to 2.1.2
+### Significant changes relative to 2.1.2:
 
 1. Fixed a regression introduced by 2.0 beta1[7] whereby cjpeg compressed PGM
 input files into full-color JPEG images unless the `-grayscale` option was
@@ -60,7 +356,7 @@ be reproduced using the libjpeg API, not using djpeg.
 2.1.2
 =====
 
-### Significant changes relative to 2.1.1
+### Significant changes relative to 2.1.1:
 
 1. Fixed a regression introduced by 2.1 beta1[13] that caused the remaining
 GAS implementations of AArch64 (Arm 64-bit) Neon SIMD functions (which are used
@@ -92,7 +388,7 @@ image contains incomplete or corrupt image data.
 2.1.1
 =====
 
-### Significant changes relative to 2.1.0
+### Significant changes relative to 2.1.0:
 
 1. Fixed a regression introduced in 2.1.0 that caused build failures with
 non-GCC-compatible compilers for Un*x/Arm platforms.
@@ -121,11 +417,11 @@ transform a specially-crafted malformed JPEG image.
 2.1.0
 =====
 
-### Significant changes relative to 2.1 beta1
+### Significant changes relative to 2.1 beta1:
 
-1. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
-decompress certain progressive JPEG images with one or more component planes of
-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
@@ -156,10 +452,10 @@ progressive JPEG format described in the report
 ["Two Issues with the JPEG Standard"](https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf).
 
 7. The PPM reader now throws an error, rather than segfaulting (due to a buffer
-overrun) or generating incorrect pixels, if an application attempts to use the
-`tjLoadImage()` function to load a 16-bit binary PPM file (a binary PPM file
-with a maximum value greater than 255) into a grayscale image buffer or to load
-a 16-bit binary PGM file into an RGB image buffer.
+overrun, CVE-2021-46822) or generating incorrect pixels, if an application
+attempts to use the `tjLoadImage()` function to load a 16-bit binary PPM file
+(a binary PPM file with a maximum value greater than 255) into a grayscale
+image buffer or to load a 16-bit binary PGM file into an RGB image buffer.
 
 8. Fixed an issue in the PPM reader that caused incorrect pixels to be
 generated when using the `tjLoadImage()` function to load a 16-bit binary PPM
@@ -325,11 +621,11 @@ methods in the TurboJPEG Java API.
 
 2. Fixed or worked around multiple issues with `jpeg_skip_scanlines()`:
 
-     - Fixed segfaults or "Corrupt JPEG data: premature end of data segment"
-errors in `jpeg_skip_scanlines()` that occurred when decompressing 4:2:2 or
-4:2:0 JPEG images using merged (non-fancy) upsampling/color conversion (that
-is, when setting `cinfo.do_fancy_upsampling` to `FALSE`.)  2.0.0[6] was a
-similar fix, but it did not cover all cases.
+     - Fixed segfaults (CVE-2020-35538) or "Corrupt JPEG data: premature end of
+data segment" errors in `jpeg_skip_scanlines()` that occurred when
+decompressing 4:2:2 or 4:2:0 JPEG images using merged (non-fancy)
+upsampling/color conversion (that is, when setting `cinfo.do_fancy_upsampling`
+to `FALSE`.)  2.0.0[6] was a similar fix, but it did not cover all cases.
      - `jpeg_skip_scanlines()` now throws an error if two-pass color
 quantization is enabled.  Two-pass color quantization never worked properly
 with `jpeg_skip_scanlines()`, and the issues could not readily be fixed.
@@ -1364,7 +1660,7 @@ features (such as the colorspace extensions), but in general, it performs no
 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.
 
index d753e1d..bf8a7fd 100644 (file)
@@ -91,7 +91,7 @@ best of our understanding.
 The Modified (3-clause) BSD License
 ===================================
 
-Copyright (C)2009-2022 D. R. Commander.  All Rights Reserved.<br>
+Copyright (C)2009-2023 D. R. Commander.  All Rights Reserved.<br>
 Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
 
 Redistribution and use in source and binary forms, with or without
index 9453c19..8f37682 100644 (file)
@@ -43,7 +43,7 @@ User documentation:
   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.
+  example.c         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.
 
@@ -68,17 +68,17 @@ other abrupt features may not compress well with JPEG, and a higher JPEG
 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.)
-
-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
+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, 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,
@@ -241,7 +241,7 @@ This software implements ITU T.81 | ISO/IEC 10918 with some extensions from
 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
index 01e391e..923e61d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -21,7 +21,26 @@ derivative of libjpeg v6b developed by Miyasaka Masaru.  The TigerVNC and
 VirtualGL projects made numerous enhancements to the codec in 2009, and in
 early 2010, libjpeg-turbo spun off into an independent project, with the goal
 of making high-speed JPEG compression/decompression technology available to a
-broader range of users and developers.
+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.
+
+[![Sponsor libjpeg-turbo](https://img.shields.io/github/sponsors/libjpeg-turbo?label=Sponsor&logo=GitHub)](https://github.com/sponsors/libjpeg-turbo)
 
 
 License
@@ -245,16 +264,6 @@ programs that need them, without breaking ABI compatibility for programs that
 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 +283,35 @@ Mathematical Compatibility
 ==========================
 
 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:
-
-- 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.
+v6b.  There are two exceptions:
+
+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.
+
+2. When using the floating point DCT/IDCT, the outputs of libjpeg v6b and
+libjpeg-turbo can differ for the following reasons:
+
+    - 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
index 082687c..471b9a3 100644 (file)
--- a/cdjpeg.h
+++ b/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,6 +35,10 @@ struct cjpeg_source_struct {
   FILE *input_file;
 
   JSAMPARRAY buffer;
+  J12SAMPARRAY buffer12;
+#ifdef C_LOSSLESS_SUPPORTED
+  J16SAMPARRAY buffer16;
+#endif
   JDIMENSION buffer_height;
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
   JDIMENSION max_pixels;
@@ -75,6 +79,10 @@ struct djpeg_dest_struct {
    * height is buffer_height.
    */
   JSAMPARRAY buffer;
+  J12SAMPARRAY buffer12;
+#ifdef D_LOSSLESS_SUPPORTED
+  J16SAMPARRAY buffer16;
+#endif
   JDIMENSION buffer_height;
 };
 
@@ -108,9 +116,23 @@ EXTERN(cjpeg_source_ptr) jinit_read_bmp(j_compress_ptr cinfo,
 EXTERN(djpeg_dest_ptr) jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2,
                                        boolean use_inversion_array);
 EXTERN(cjpeg_source_ptr) jinit_read_gif(j_compress_ptr cinfo);
+EXTERN(cjpeg_source_ptr) j12init_read_gif(j_compress_ptr cinfo);
+#ifdef C_LOSSLESS_SUPPORTED
+EXTERN(cjpeg_source_ptr) j16init_read_gif(j_compress_ptr cinfo);
+#endif
 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 +149,7 @@ EXTERN(boolean) set_sample_factors(j_compress_ptr cinfo, char *arg);
 /* 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 +179,3 @@ EXTERN(FILE *) write_stdout(void);
 #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.1 b/cjpeg.1
index 4bc4c8f..0815ca0 100644 (file)
--- a/cjpeg.1
+++ b/cjpeg.1
@@ -1,4 +1,4 @@
-.TH CJPEG 1 "30 November 2021"
+.TH CJPEG 1 "29 June 2023"
 .SH NAME
 cjpeg \- compress an image file to a JPEG file
 .SH SYNOPSIS
@@ -149,6 +149,56 @@ about the same --- often a little smaller.
 .PP
 Switches for advanced users:
 .TP
+.BI \-precision " N"
+Create JPEG file with N-bit data precision.  N is 8, 12, or 16; default is 8.
+If N is 16, then
+.B -lossless
+must also be specified.
+.B Caution:
+12-bit and 16-bit JPEG is not yet widely implemented, so many decoders will be
+unable to view a 12-bit or 16-bit JPEG file at all.
+.TP
+.BI \-lossless " psv[,Pt]"
+Create a lossless JPEG file using the specified predictor selection value
+(1 through 7) and optional point transform (0 through
+.nh
+.I precision
+.hy
+- 1, where
+.nh
+.I precision
+.hy
+is the JPEG data precision in bits).  A point transform value of 0 (the
+default) is necessary in order to create a fully lossless JPEG file.  (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.)
+.B Caution:
+lossless JPEG is not yet widely implemented, so many decoders will be unable to
+view a lossless JPEG file at all.  Note that the following features will be
+unavailable when compressing or decompressing a lossless JPEG file:
+.IP
+- Quality/quantization table selection
+.IP
+- Color space conversion (the JPEG image will use the same color space as the
+input image)
+.IP
+- Color quantization
+.IP
+- DCT/IDCT algorithm selection
+.IP
+- Smoothing
+.IP
+- Downsampling/upsampling
+.IP
+- IDCT scaling
+.IP
+- Partial image decompression
+.IP
+- Transformations using
+.B jpegtran
+.IP
+Any switches used to enable or configure those features will be ignored.
+.TP
 .B \-arithmetic
 Use arithmetic coding.
 .B Caution:
@@ -195,8 +245,8 @@ machines.
 Embed ICC color management profile contained in the specified file.
 .TP
 .BI \-restart " N"
-Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
-attached to the number.
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks (samples in
+lossless mode) if "B" is attached to the number.
 .B \-restart 0
 (the default) means no restart markers.
 .TP
diff --git a/cjpeg.c b/cjpeg.c
index dae18a3..ed649d2 100644 (file)
--- a/cjpeg.c
+++ b/cjpeg.c
@@ -4,6 +4,8 @@
  * 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.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -103,11 +105,31 @@ select_file_type(j_compress_ptr cinfo, FILE *infile)
 #endif
 #ifdef GIF_SUPPORTED
   case 'G':
-    return jinit_read_gif(cinfo);
+    if (cinfo->data_precision == 16) {
+#ifdef C_LOSSLESS_SUPPORTED
+      return j16init_read_gif(cinfo);
+#else
+      ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+      break;
+#endif
+    } else if (cinfo->data_precision == 12)
+      return j12init_read_gif(cinfo);
+    else
+      return jinit_read_gif(cinfo);
 #endif
 #ifdef PPM_SUPPORTED
   case 'P':
-    return jinit_read_ppm(cinfo);
+    if (cinfo->data_precision == 16) {
+#ifdef C_LOSSLESS_SUPPORTED
+      return j16init_read_ppm(cinfo);
+#else
+      ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+      break;
+#endif
+    } else if (cinfo->data_precision == 12)
+      return j12init_read_ppm(cinfo);
+    else
+      return jinit_read_ppm(cinfo);
 #endif
 #ifdef TARGA_SUPPORTED
   case 0x00:
@@ -204,6 +226,16 @@ usage(void)
   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 is 8, 12, or 16; default is 8; if N is 16, 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 +258,7 @@ usage(void)
 #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 +289,9 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
 {
   int argn;
   char *arg;
+#ifdef C_LOSSLESS_SUPPORTED
+  int psv, pt = 0;
+#endif
   boolean force_baseline;
   boolean simple_progressive;
   char *qualityarg = NULL;      /* saves -quality parm if any */
@@ -355,6 +388,27 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
         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);
+      jpeg_enable_lossless(cinfo, psv, pt);
+#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,7 +438,23 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
         usage();
       outfilename = argv[argn]; /* save it away for later use */
 
-    } else if (keymatch(arg, "progressive", 1)) {
+    } 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 != 8 && val != 12 && val != 16)
+#else
+      if (val != 8 && val != 12)
+#endif
+        usage();
+      cinfo->data_precision = val;
+
+    } else if (keymatch(arg, "progressive", 3)) {
       /* Select simple progressive mode. */
 #ifdef C_PROGRESSIVE_SUPPORTED
       simple_progressive = TRUE;
@@ -397,13 +467,7 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv,
 
     } 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). */
@@ -710,11 +774,9 @@ main(int argc, char **argv)
   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
@@ -729,9 +791,25 @@ main(int argc, char **argv)
     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 == 16) {
+#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
+  } 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 {
+    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);
+    }
   }
 
   /* Finish compression and release memory */
index 7d6fa2c..2e0170f 100644 (file)
@@ -90,7 +90,7 @@ if(WITH_JAVA)
   set(INST_DEFS ${INST_DEFS} -DJAVA)
 endif()
 
-if(MSVC_IDE)
+if(GENERATOR_IS_MULTI_CONFIG)
   set(INST_DEFS ${INST_DEFS} "-DBUILDDIR=${CMAKE_CFG_INTDIR}\\")
 else()
   set(INST_DEFS ${INST_DEFS} "-DBUILDDIR=")
index fc3fc25..6b5a146 100644 (file)
@@ -30,6 +30,14 @@ file(GLOB FILES
   *_411_*.ppm
   *_411_*.jpg
   *_411.yuv
+  *_441_*.bmp
+  *_441_*.png
+  *_441_*.ppm
+  *_441_*.jpg
+  *_441.yuv
+  *_LOSSL*S_*.bmp
+  *_LOSSL*S_*.ppm
+  *_LOSSL*S_*.jpg
   tjbenchtest*.log
   tjexampletest*.log)
 
diff --git a/cmakescripts/tjbenchtest.cmake b/cmakescripts/tjbenchtest.cmake
new file mode 100644 (file)
index 0000000..facb203
--- /dev/null
@@ -0,0 +1,77 @@
+if(NOT DEFINED PRECISION)
+  message(FATAL_ERROR "PRECISION must be specified")
+endif()
+
+if(NOT DEFINED WITH_JAVA)
+  message(FATAL_ERROR "WITH_JAVA must be specified")
+endif()
+
+macro(check_error program)
+  if(NOT RESULT EQUAL 0)
+    message(FATAL_ERROR "${program} failed.")
+  endif()
+endmacro()
+
+macro(run_test PROG ARGS)
+  string(REPLACE ";" " " SPACED_ARGS "${ARGS}")
+  message(STATUS "${PROG} ${SPACED_ARGS}")
+  execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${PROG} ${ARGS}
+    RESULT_VARIABLE RESULT)
+  check_error("${PROG} ${SPACED_ARGS}")
+endmacro()
+
+if(NOT PRECISION EQUAL 16)
+  run_test(tjbenchtest "-precision;${PRECISION}")
+  run_test(tjbenchtest "-precision;${PRECISION};-alloc")
+endif()
+if(PRECISION EQUAL 8)
+  run_test(tjbenchtest "-precision;${PRECISION};-yuv")
+  run_test(tjbenchtest "-precision;${PRECISION};-yuv;-alloc")
+  run_test(tjbenchtest "-precision;${PRECISION};-optimize")
+  run_test(tjbenchtest "-precision;${PRECISION};-optimize;-yuv")
+endif()
+if(NOT PRECISION EQUAL 16)
+  run_test(tjbenchtest "-precision;${PRECISION};-progressive")
+endif()
+if(PRECISION EQUAL 8)
+  run_test(tjbenchtest "-precision;${PRECISION};-progressive;-yuv")
+endif()
+if(NOT PRECISION EQUAL 16)
+  run_test(tjbenchtest "-precision;${PRECISION};-arithmetic")
+  run_test(tjbenchtest "-precision;${PRECISION};-progressive;-arithmetic")
+endif()
+if(PRECISION EQUAL 8)
+  run_test(tjbenchtest "-precision;${PRECISION};-arithmetic;-yuv")
+endif()
+run_test(tjbenchtest "-precision;${PRECISION};-lossless")
+run_test(tjbenchtest "-precision;${PRECISION};-lossless;-alloc")
+if(PRECISION EQUAL 8)
+  run_test(tjexampletest "")
+endif()
+if(WITH_JAVA)
+  if(NOT PRECISION EQUAL 16)
+    run_test(tjbenchtest "-java;-precision;${PRECISION}")
+  endif()
+  if(PRECISION EQUAL 8)
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-yuv")
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-optimize")
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-optimize;-yuv")
+  endif()
+  if(NOT PRECISION EQUAL 16)
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-progressive")
+  endif()
+  if(PRECISION EQUAL 8)
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-progressive;-yuv")
+  endif()
+  if(NOT PRECISION EQUAL 16)
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-arithmetic")
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-progressive;-arithmetic")
+  endif()
+  if(PRECISION EQUAL 8)
+    run_test(tjbenchtest "-java;-precision;${PRECISION};-arithmetic;-yuv")
+  endif()
+  run_test(tjbenchtest "-java;-precision;${PRECISION};-lossless")
+  if(PRECISION EQUAL 8)
+    run_test(tjexampletest "-java")
+  endif()
+endif()
diff --git a/cmyk.h b/cmyk.h
index 48187a8..2389124 100644 (file)
--- a/cmyk.h
+++ b/cmyk.h
@@ -1,7 +1,7 @@
 /*
  * cmyk.h
  *
- * Copyright (C) 2017-2018, D. R. Commander.
+ * Copyright (C) 2017-2018, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #include <jinclude.h>
 #define JPEG_INTERNALS
 #include <jpeglib.h>
-#include "jconfigint.h"
+#include "jsamplecomp.h"
 
 
 /* Fully reversible */
 
 INLINE
 LOCAL(void)
-rgb_to_cmyk(JSAMPLE r, JSAMPLE g, JSAMPLE b, JSAMPLE *c, JSAMPLE *m,
-            JSAMPLE *y, JSAMPLE *k)
+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 ctmp = 1.0 - ((double)r / (double)_MAXJSAMPLE);
+  double mtmp = 1.0 - ((double)g / (double)_MAXJSAMPLE);
+  double ytmp = 1.0 - ((double)b / (double)_MAXJSAMPLE);
   double ktmp = MIN(MIN(ctmp, mtmp), ytmp);
 
   if (ktmp == 1.0) ctmp = mtmp = ytmp = 0.0;
@@ -38,10 +38,10 @@ rgb_to_cmyk(JSAMPLE r, JSAMPLE g, JSAMPLE b, JSAMPLE *c, JSAMPLE *m,
     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);
+  *c = (_JSAMPLE)((double)_MAXJSAMPLE - ctmp * (double)_MAXJSAMPLE + 0.5);
+  *m = (_JSAMPLE)((double)_MAXJSAMPLE - mtmp * (double)_MAXJSAMPLE + 0.5);
+  *y = (_JSAMPLE)((double)_MAXJSAMPLE - ytmp * (double)_MAXJSAMPLE + 0.5);
+  *k = (_JSAMPLE)((double)_MAXJSAMPLE - ktmp * (double)_MAXJSAMPLE + 0.5);
 }
 
 
@@ -49,12 +49,12 @@ rgb_to_cmyk(JSAMPLE r, JSAMPLE g, JSAMPLE b, JSAMPLE *c, JSAMPLE *m,
 
 INLINE
 LOCAL(void)
-cmyk_to_rgb(JSAMPLE c, JSAMPLE m, JSAMPLE y, JSAMPLE k, JSAMPLE *r, JSAMPLE *g,
-            JSAMPLE *b)
+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);
+  *r = (_JSAMPLE)((double)c * (double)k / (double)_MAXJSAMPLE + 0.5);
+  *g = (_JSAMPLE)((double)m * (double)k / (double)_MAXJSAMPLE + 0.5);
+  *b = (_JSAMPLE)((double)y * (double)k / (double)_MAXJSAMPLE + 0.5);
 }
 
 
diff --git a/djpeg.c b/djpeg.c
index 7666e3f..4ea5c4b 100644 (file)
--- a/djpeg.c
+++ b/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-2023, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -164,9 +164,7 @@ usage(void)
   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");
@@ -316,7 +314,9 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
       if (++argn >= argc)       /* advance to next argument */
         usage();
       icc_filename = argv[argn];
+#ifdef SAVE_MARKERS_SUPPORTED
       jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xFFFF);
+#endif
 
     } else if (keymatch(arg, "map", 3)) {
       /* Quantize to a color map taken from an input file. */
@@ -330,7 +330,10 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
           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
@@ -377,13 +380,7 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
 
     } 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. */
@@ -535,9 +532,7 @@ main(int argc, char **argv)
   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];
@@ -627,7 +622,6 @@ main(int argc, char **argv)
   }
 
   /* Specify data source for decompression */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
   if (memsrc) {
     size_t nbytes;
     do {
@@ -649,7 +643,6 @@ main(int argc, char **argv)
     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 */
@@ -672,7 +665,12 @@ main(int argc, char **argv)
 #endif
 #ifdef GIF_SUPPORTED
   case FMT_GIF:
-    dest_mgr = jinit_write_gif(&cinfo, TRUE);
+    if (cinfo.data_precision == 16)
+      ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+    else if (cinfo.data_precision == 12)
+      dest_mgr = j12init_write_gif(&cinfo, TRUE);
+    else
+      dest_mgr = jinit_write_gif(&cinfo, TRUE);
     break;
   case FMT_GIF0:
     dest_mgr = jinit_write_gif(&cinfo, FALSE);
@@ -680,7 +678,16 @@ main(int argc, char **argv)
 #endif
 #ifdef PPM_SUPPORTED
   case FMT_PPM:
-    dest_mgr = jinit_write_ppm(&cinfo);
+    if (cinfo.data_precision == 16)
+#ifdef D_LOSSLESS_SUPPORTED
+      dest_mgr = j16init_write_ppm(&cinfo);
+#else
+      ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision);
+#endif
+    else if (cinfo.data_precision == 12)
+      dest_mgr = j12init_write_ppm(&cinfo);
+    else
+      dest_mgr = jinit_write_ppm(&cinfo);
     break;
 #endif
 #ifdef TARGA_SUPPORTED
@@ -719,22 +726,44 @@ main(int argc, char **argv)
     (*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);
-      exit(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 == 16)
+      ERREXIT(&cinfo, JERR_NOTIMPL);
+    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);
+        exit(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 {
+      /* 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);
+        exit(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);
+      }
     }
 
   /* Decompress a subregion */
@@ -751,7 +780,12 @@ main(int argc, char **argv)
       exit(EXIT_FAILURE);
     }
 
-    jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
+    if (cinfo.data_precision == 16)
+      ERREXIT(&cinfo, JERR_NOTIMPL);
+    else if (cinfo.data_precision == 12)
+      jpeg12_crop_scanline(&cinfo, &crop_x, &crop_width);
+    else
+      jpeg_crop_scanline(&cinfo, &crop_x, &crop_width);
     if (dest_mgr->calc_buffer_dimensions)
       (*dest_mgr->calc_buffer_dimensions) (&cinfo, dest_mgr);
     else
@@ -765,24 +799,48 @@ main(int argc, char **argv)
     (*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);
-      exit(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);
-      exit(EXIT_FAILURE);
+    if (cinfo.data_precision == 16)
+      ERREXIT(&cinfo, JERR_NOTIMPL);
+    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);
+        exit(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);
+        exit(EXIT_FAILURE);
+      }
+    } else {
+      /* 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);
+        exit(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);
+        exit(EXIT_FAILURE);
+      }
     }
 
   /* Normal full-image decompress */
@@ -790,11 +848,31 @@ main(int argc, char **argv)
     /* 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 == 16) {
+#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
+    } 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 {
+      /* 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);
+      }
     }
   }
 
index c735a5a..d7e2987 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
index 42f38f6..78730e6 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
index 5de4c6f..22c164b 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
@@ -65,7 +65,7 @@ $(function() {
 <div class="contents">
 <div class="textblock">Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:</div><ul>
 <li>customFilter
-: <a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">tjtransform</a>
+: <a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">tjtransform</a>
 </li>
 <li>data
 : <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a>
index 2b010f4..0e3897e 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
@@ -65,7 +65,7 @@ $(function() {
 <div class="contents">
 &#160;<ul>
 <li>customFilter
-: <a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">tjtransform</a>
+: <a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">tjtransform</a>
 </li>
 <li>data
 : <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a>
index 63d4791..04285c2 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
@@ -92,6 +92,9 @@ Data Structures</h2></td></tr>
 </table><table class="memberdecls">
 <tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="define-members"></a>
 Macros</h2></td></tr>
+<tr class="memitem:ga5e0e8c784295c636f0bf8dab93c4bddf"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5e0e8c784295c636f0bf8dab93c4bddf">TJ_NUMINIT</a></td></tr>
+<tr class="memdesc:ga5e0e8c784295c636f0bf8dab93c4bddf"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of initialization options.  <a href="group___turbo_j_p_e_g.html#ga5e0e8c784295c636f0bf8dab93c4bddf">More...</a><br /></td></tr>
+<tr class="separator:ga5e0e8c784295c636f0bf8dab93c4bddf"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga5ef3d169162ce77ce348e292a0b7477c"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5ef3d169162ce77ce348e292a0b7477c">TJ_NUMSAMP</a></td></tr>
 <tr class="memdesc:ga5ef3d169162ce77ce348e292a0b7477c"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of chrominance subsampling options.  <a href="group___turbo_j_p_e_g.html#ga5ef3d169162ce77ce348e292a0b7477c">More...</a><br /></td></tr>
 <tr class="separator:ga5ef3d169162ce77ce348e292a0b7477c"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -101,30 +104,9 @@ Macros</h2></td></tr>
 <tr class="memitem:ga39f57a6fb02d9cf32e7b6890099b5a71"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga39f57a6fb02d9cf32e7b6890099b5a71">TJ_NUMCS</a></td></tr>
 <tr class="memdesc:ga39f57a6fb02d9cf32e7b6890099b5a71"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of JPEG colorspaces.  <a href="group___turbo_j_p_e_g.html#ga39f57a6fb02d9cf32e7b6890099b5a71">More...</a><br /></td></tr>
 <tr class="separator:ga39f57a6fb02d9cf32e7b6890099b5a71"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga72ecf4ebe6eb702d3c6f5ca27455e1ec"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">TJFLAG_BOTTOMUP</a></td></tr>
-<tr class="memdesc:ga72ecf4ebe6eb702d3c6f5ca27455e1ec"><td class="mdescLeft">&#160;</td><td class="mdescRight">The uncompressed source/destination image is stored in bottom-up (Windows, OpenGL) order, not top-down (X11) order.  <a href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">More...</a><br /></td></tr>
-<tr class="separator:ga72ecf4ebe6eb702d3c6f5ca27455e1ec"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga4ee4506c81177a06f77e2504a22efd2d"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga4ee4506c81177a06f77e2504a22efd2d">TJFLAG_FASTUPSAMPLE</a></td></tr>
-<tr class="memdesc:ga4ee4506c81177a06f77e2504a22efd2d"><td class="mdescLeft">&#160;</td><td class="mdescRight">When decompressing an image that was compressed using chrominance subsampling, use the fastest chrominance upsampling algorithm available in the underlying codec.  <a href="group___turbo_j_p_e_g.html#ga4ee4506c81177a06f77e2504a22efd2d">More...</a><br /></td></tr>
-<tr class="separator:ga4ee4506c81177a06f77e2504a22efd2d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga8808d403c68b62aaa58a4c1e58e98963"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963">TJFLAG_NOREALLOC</a></td></tr>
-<tr class="memdesc:ga8808d403c68b62aaa58a4c1e58e98963"><td class="mdescLeft">&#160;</td><td class="mdescRight">Disable buffer (re)allocation.  <a href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963">More...</a><br /></td></tr>
-<tr class="separator:ga8808d403c68b62aaa58a4c1e58e98963"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaabce235db80d3f698b27f36cbd453da2"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaabce235db80d3f698b27f36cbd453da2">TJFLAG_FASTDCT</a></td></tr>
-<tr class="memdesc:gaabce235db80d3f698b27f36cbd453da2"><td class="mdescLeft">&#160;</td><td class="mdescRight">Use the fastest DCT/IDCT algorithm available in the underlying codec.  <a href="group___turbo_j_p_e_g.html#gaabce235db80d3f698b27f36cbd453da2">More...</a><br /></td></tr>
-<tr class="separator:gaabce235db80d3f698b27f36cbd453da2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gacb233cfd722d66d1ccbf48a7de81f0e0"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">TJFLAG_ACCURATEDCT</a></td></tr>
-<tr class="memdesc:gacb233cfd722d66d1ccbf48a7de81f0e0"><td class="mdescLeft">&#160;</td><td class="mdescRight">Use the most accurate DCT/IDCT algorithm available in the underlying codec.  <a href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">More...</a><br /></td></tr>
-<tr class="separator:gacb233cfd722d66d1ccbf48a7de81f0e0"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga519cfa4ef6c18d9e5b455fdf59306a3a"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga519cfa4ef6c18d9e5b455fdf59306a3a">TJFLAG_STOPONWARNING</a></td></tr>
-<tr class="memdesc:ga519cfa4ef6c18d9e5b455fdf59306a3a"><td class="mdescLeft">&#160;</td><td class="mdescRight">Immediately discontinue the current compression/decompression/transform operation if the underlying codec throws a warning (non-fatal error).  <a href="group___turbo_j_p_e_g.html#ga519cfa4ef6c18d9e5b455fdf59306a3a">More...</a><br /></td></tr>
-<tr class="separator:ga519cfa4ef6c18d9e5b455fdf59306a3a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga43b426750b46190a25d34a67ef76df1b"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga43b426750b46190a25d34a67ef76df1b">TJFLAG_PROGRESSIVE</a></td></tr>
-<tr class="memdesc:ga43b426750b46190a25d34a67ef76df1b"><td class="mdescLeft">&#160;</td><td class="mdescRight">Use progressive entropy coding in JPEG images generated by the compression and transform functions.  <a href="group___turbo_j_p_e_g.html#ga43b426750b46190a25d34a67ef76df1b">More...</a><br /></td></tr>
-<tr class="separator:ga43b426750b46190a25d34a67ef76df1b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga163e6482dc5096831feef9c79ff3f805"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga163e6482dc5096831feef9c79ff3f805">TJFLAG_LIMITSCANS</a></td></tr>
-<tr class="memdesc:ga163e6482dc5096831feef9c79ff3f805"><td class="mdescLeft">&#160;</td><td class="mdescRight">Limit the number of progressive JPEG scans that the decompression and transform functions will process.  <a href="group___turbo_j_p_e_g.html#ga163e6482dc5096831feef9c79ff3f805">More...</a><br /></td></tr>
-<tr class="separator:ga163e6482dc5096831feef9c79ff3f805"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa628be5db276fc3676dfba205d45d780"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa628be5db276fc3676dfba205d45d780">TJ_NUMPARAM</a></td></tr>
+<tr class="memdesc:gaa628be5db276fc3676dfba205d45d780"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of parameters.  <a href="group___turbo_j_p_e_g.html#gaa628be5db276fc3676dfba205d45d780">More...</a><br /></td></tr>
+<tr class="separator:gaa628be5db276fc3676dfba205d45d780"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga79bde1b4a3e2351e00887e47781b966e"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga79bde1b4a3e2351e00887e47781b966e">TJ_NUMERR</a></td></tr>
 <tr class="memdesc:ga79bde1b4a3e2351e00887e47781b966e"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of error codes.  <a href="group___turbo_j_p_e_g.html#ga79bde1b4a3e2351e00887e47781b966e">More...</a><br /></td></tr>
 <tr class="separator:ga79bde1b4a3e2351e00887e47781b966e"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -132,29 +114,32 @@ Macros</h2></td></tr>
 <tr class="memdesc:ga0f6dbd18adf38b7d46ac547f0f4d562c"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of transform operations.  <a href="group___turbo_j_p_e_g.html#ga0f6dbd18adf38b7d46ac547f0f4d562c">More...</a><br /></td></tr>
 <tr class="separator:ga0f6dbd18adf38b7d46ac547f0f4d562c"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga50e03cb5ed115330e212417429600b00"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00">TJXOPT_PERFECT</a></td></tr>
-<tr class="memdesc:ga50e03cb5ed115330e212417429600b00"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to return an error if the transform is not perfect.  <a href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00">More...</a><br /></td></tr>
+<tr class="memdesc:ga50e03cb5ed115330e212417429600b00"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> to return an error if the transform is not perfect.  <a href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00">More...</a><br /></td></tr>
 <tr class="separator:ga50e03cb5ed115330e212417429600b00"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga319826b7eb1583c0595bbe7b95428709"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga319826b7eb1583c0595bbe7b95428709">TJXOPT_TRIM</a></td></tr>
-<tr class="memdesc:ga319826b7eb1583c0595bbe7b95428709"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to discard any partial MCU blocks that cannot be transformed.  <a href="group___turbo_j_p_e_g.html#ga319826b7eb1583c0595bbe7b95428709">More...</a><br /></td></tr>
+<tr class="memdesc:ga319826b7eb1583c0595bbe7b95428709"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> to discard any partial MCU blocks that cannot be transformed.  <a href="group___turbo_j_p_e_g.html#ga319826b7eb1583c0595bbe7b95428709">More...</a><br /></td></tr>
 <tr class="separator:ga319826b7eb1583c0595bbe7b95428709"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga9c771a757fc1294add611906b89ab2d2"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2">TJXOPT_CROP</a></td></tr>
 <tr class="memdesc:ga9c771a757fc1294add611906b89ab2d2"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable lossless cropping.  <a href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2">More...</a><br /></td></tr>
 <tr class="separator:ga9c771a757fc1294add611906b89ab2d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga3acee7b48ade1b99e5588736007c2589"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589">TJXOPT_GRAY</a></td></tr>
-<tr class="memdesc:ga3acee7b48ade1b99e5588736007c2589"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will discard the color data in the input image and produce a grayscale output image.  <a href="group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589">More...</a><br /></td></tr>
+<tr class="memdesc:ga3acee7b48ade1b99e5588736007c2589"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will discard the color data in the source image and produce a grayscale destination image.  <a href="group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589">More...</a><br /></td></tr>
 <tr class="separator:ga3acee7b48ade1b99e5588736007c2589"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gafbf992bbf6e006705886333703ffab31"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31">TJXOPT_NOOUTPUT</a></td></tr>
-<tr class="memdesc:gafbf992bbf6e006705886333703ffab31"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> 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.)  <a href="group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31">More...</a><br /></td></tr>
+<tr class="memdesc:gafbf992bbf6e006705886333703ffab31"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> from outputting a JPEG image for this particular transform.  <a href="group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31">More...</a><br /></td></tr>
 <tr class="separator:gafbf992bbf6e006705886333703ffab31"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gad2371c80674584ecc1a7d75e564cf026"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026">TJXOPT_PROGRESSIVE</a></td></tr>
-<tr class="memdesc:gad2371c80674584ecc1a7d75e564cf026"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable progressive entropy coding in the output image generated by this particular transform.  <a href="group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026">More...</a><br /></td></tr>
+<tr class="memdesc:gad2371c80674584ecc1a7d75e564cf026"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable progressive entropy coding in the JPEG image generated by this particular transform.  <a href="group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026">More...</a><br /></td></tr>
 <tr class="separator:gad2371c80674584ecc1a7d75e564cf026"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga153b468cfb905d0de61706c838986fe8"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga153b468cfb905d0de61706c838986fe8">TJXOPT_COPYNONE</a></td></tr>
-<tr class="memdesc:ga153b468cfb905d0de61706c838986fe8"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> from copying any extra markers (including EXIF and ICC profile data) from the source image to the output image.  <a href="group___turbo_j_p_e_g.html#ga153b468cfb905d0de61706c838986fe8">More...</a><br /></td></tr>
+<tr class="memdesc:ga153b468cfb905d0de61706c838986fe8"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> from copying any extra markers (including EXIF and ICC profile data) from the source image to the destination image.  <a href="group___turbo_j_p_e_g.html#ga153b468cfb905d0de61706c838986fe8">More...</a><br /></td></tr>
 <tr class="separator:ga153b468cfb905d0de61706c838986fe8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga0aba955473315e405295d978f0c16511"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511">TJPAD</a>(width)</td></tr>
-<tr class="memdesc:ga0aba955473315e405295d978f0c16511"><td class="mdescLeft">&#160;</td><td class="mdescRight">Pad the given width to the nearest 32-bit boundary.  <a href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511">More...</a><br /></td></tr>
-<tr class="separator:ga0aba955473315e405295d978f0c16511"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaecaaa3b7e2af812592c015d83207f010"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010">TJXOPT_ARITHMETIC</a></td></tr>
+<tr class="memdesc:gaecaaa3b7e2af812592c015d83207f010"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable arithmetic entropy coding in the JPEG image generated by this particular transform.  <a href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010">More...</a><br /></td></tr>
+<tr class="separator:gaecaaa3b7e2af812592c015d83207f010"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga6bedf37aa9e1122f3ec9f7302ca59117"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6bedf37aa9e1122f3ec9f7302ca59117">TJXOPT_OPTIMIZE</a></td></tr>
+<tr class="memdesc:ga6bedf37aa9e1122f3ec9f7302ca59117"><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable optimized baseline entropy coding in the JPEG image generated by this particular transform.  <a href="group___turbo_j_p_e_g.html#ga6bedf37aa9e1122f3ec9f7302ca59117">More...</a><br /></td></tr>
+<tr class="separator:ga6bedf37aa9e1122f3ec9f7302ca59117"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga84878bb65404204743aa18cac02781df"><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df">TJSCALED</a>(dimension,  scalingFactor)</td></tr>
 <tr class="memdesc:ga84878bb65404204743aa18cac02781df"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compute the scaled value of <code>dimension</code> using the given scaling factor.  <a href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df">More...</a><br /></td></tr>
 <tr class="separator:ga84878bb65404204743aa18cac02781df"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -170,6 +155,12 @@ Typedefs</h2></td></tr>
 </table><table class="memberdecls">
 <tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="enum-members"></a>
 Enumerations</h2></td></tr>
+<tr class="memitem:ga3850bbee1313e752e667b4eb08b1e086"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086">TJINIT</a> { <a class="el" href="group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086aa45ac279e3dc6ffabc4b0f45864da796">TJINIT_COMPRESS</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a4b8ca1ef700699b71350700bf95c2167">TJINIT_DECOMPRESS</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a8d58a2a4c45b3e0cd349746544a6e0c2">TJINIT_TRANSFORM</a>
+ }</td></tr>
+<tr class="memdesc:ga3850bbee1313e752e667b4eb08b1e086"><td class="mdescLeft">&#160;</td><td class="mdescRight">Initialization options.  <a href="group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086">More...</a><br /></td></tr>
+<tr class="separator:ga3850bbee1313e752e667b4eb08b1e086"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga1d047060ea80bb9820d540bb928e9074"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">TJSAMP</a> { <br />
 &#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3">TJSAMP_444</a>, 
 <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a136130902cc578f11f32429b59368404">TJSAMP_422</a>, 
@@ -177,7 +168,9 @@ Enumerations</h2></td></tr>
 <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248">TJSAMP_GRAY</a>, 
 <br />
 &#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974">TJSAMP_440</a>, 
-<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2">TJSAMP_411</a>
+<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2">TJSAMP_411</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3351696e1dd34a083a35b6be8b90122d">TJSAMP_441</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074ac124fa8f6cb41147e3d670dfbdfb7173">TJSAMP_UNKNOWN</a>
 <br />
  }</td></tr>
 <tr class="memdesc:ga1d047060ea80bb9820d540bb928e9074"><td class="mdescLeft">&#160;</td><td class="mdescRight">Chrominance subsampling options.  <a href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">More...</a><br /></td></tr>
@@ -214,6 +207,39 @@ Enumerations</h2></td></tr>
  }</td></tr>
 <tr class="memdesc:ga4f83ad3368e0e29d1957be0efa7c3720"><td class="mdescLeft">&#160;</td><td class="mdescRight">JPEG colorspaces.  <a href="group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720">More...</a><br /></td></tr>
 <tr class="separator:ga4f83ad3368e0e29d1957be0efa7c3720"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa0f6be63ba78278299c9f5c12031fe82"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">TJPARAM</a> { <br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a555e2212079fa49b30bcd2879c6c8ddb">TJPARAM_STOPONWARNING</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a924657172695ed6cb0b128219546fcce">TJPARAM_BOTTOMUP</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b">TJPARAM_NOREALLOC</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0467e8792621f2d817dc2af563d3186c">TJPARAM_QUALITY</a>, 
+<br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a">TJPARAM_SUBSAMP</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8">TJPARAM_JPEGWIDTH</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f">TJPARAM_JPEGHEIGHT</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a781db82741934e8cd008d308597c59d8">TJPARAM_PRECISION</a>, 
+<br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a46a10d46309514907d0c39fcd86c324c">TJPARAM_COLORSPACE</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0e051ac106f7b7402b690a5daf4869c0">TJPARAM_FASTUPSAMPLE</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a6914692ac6ec5567787d592b7563f627">TJPARAM_FASTDCT</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6">TJPARAM_OPTIMIZE</a>, 
+<br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f">TJPARAM_PROGRESSIVE</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ac478910e20ecf61b914f9824d80f8167">TJPARAM_SCANLIMIT</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7">TJPARAM_ARITHMETIC</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f">TJPARAM_LOSSLESS</a>, 
+<br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abcc997d40e5bec84817c12b76ef84159">TJPARAM_LOSSLESSPSV</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4a6c6f25764ecaf4231a36bff844e46a">TJPARAM_LOSSLESSPT</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec">TJPARAM_RESTARTBLOCKS</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a714367585952fe5c863f0dba5bd37e5c">TJPARAM_RESTARTROWS</a>, 
+<br />
+&#160;&#160;<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4de5c9d7cab5be806143a43c3b0e0877">TJPARAM_XDENSITY</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abda48f2df7eb9b88e2b7621efb017eba">TJPARAM_YDENSITY</a>, 
+<a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4c045981bd8a303521a401dbbe1df208">TJPARAM_DENSITYUNITS</a>
+<br />
+ }</td></tr>
+<tr class="memdesc:gaa0f6be63ba78278299c9f5c12031fe82"><td class="mdescLeft">&#160;</td><td class="mdescRight">Parameters.  <a href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">More...</a><br /></td></tr>
+<tr class="separator:gaa0f6be63ba78278299c9f5c12031fe82"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gafbc17cfa57d0d5d11fea35ac025950fe"><td class="memItemLeft" align="right" valign="top">enum &#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe">TJERR</a> { <a class="el" href="group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59">TJERR_WARNING</a>, 
 <a class="el" href="group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a">TJERR_FATAL</a>
  }</td></tr>
@@ -231,95 +257,125 @@ Enumerations</h2></td></tr>
 <a class="el" href="group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08">TJXOP_ROT270</a>
 <br />
  }</td></tr>
-<tr class="memdesc:ga2de531af4e7e6c4f124908376b354866"><td class="mdescLeft">&#160;</td><td class="mdescRight">Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>  <a href="group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866">More...</a><br /></td></tr>
+<tr class="memdesc:ga2de531af4e7e6c4f124908376b354866"><td class="mdescLeft">&#160;</td><td class="mdescRight">Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a>  <a href="group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866">More...</a><br /></td></tr>
 <tr class="separator:ga2de531af4e7e6c4f124908376b354866"><td class="memSeparator" colspan="2">&#160;</td></tr>
 </table><table class="memberdecls">
 <tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="func-members"></a>
 Functions</h2></td></tr>
-<tr class="memitem:ga9d63a05fc6d813f4aae06107041a37e8"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9d63a05fc6d813f4aae06107041a37e8">tjInitCompress</a> (void)</td></tr>
-<tr class="memdesc:ga9d63a05fc6d813f4aae06107041a37e8"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG compressor instance.  <a href="group___turbo_j_p_e_g.html#ga9d63a05fc6d813f4aae06107041a37e8">More...</a><br /></td></tr>
-<tr class="separator:ga9d63a05fc6d813f4aae06107041a37e8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gafbdce0112fd78fd38efae841443a9bcf"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gafbdce0112fd78fd38efae841443a9bcf">tjCompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> 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)</td></tr>
-<tr class="memdesc:gafbdce0112fd78fd38efae841443a9bcf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an RGB, grayscale, or CMYK image into a JPEG image.  <a href="group___turbo_j_p_e_g.html#gafbdce0112fd78fd38efae841443a9bcf">More...</a><br /></td></tr>
-<tr class="separator:gafbdce0112fd78fd38efae841443a9bcf"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga7622a459b79aa1007e005b58783f875b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7622a459b79aa1007e005b58783f875b">tjCompressFromYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pad, int height, int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)</td></tr>
-<tr class="memdesc:ga7622a459b79aa1007e005b58783f875b"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a YUV planar image into a JPEG image.  <a href="group___turbo_j_p_e_g.html#ga7622a459b79aa1007e005b58783f875b">More...</a><br /></td></tr>
-<tr class="separator:ga7622a459b79aa1007e005b58783f875b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga29ec5dfbd2d84b8724e951d6fa0d5d9e"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga29ec5dfbd2d84b8724e951d6fa0d5d9e">tjCompressFromYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char **srcPlanes, int width, const int *strides, int height, int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)</td></tr>
-<tr class="memdesc:ga29ec5dfbd2d84b8724e951d6fa0d5d9e"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a set of Y, U (Cb), and V (Cr) image planes into a JPEG image.  <a href="group___turbo_j_p_e_g.html#ga29ec5dfbd2d84b8724e951d6fa0d5d9e">More...</a><br /></td></tr>
-<tr class="separator:ga29ec5dfbd2d84b8724e951d6fa0d5d9e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga67ac12fee79073242cb216e07c9f1f90"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90">tjBufSize</a> (int width, int height, int jpegSubsamp)</td></tr>
-<tr class="memdesc:ga67ac12fee79073242cb216e07c9f1f90"><td class="mdescLeft">&#160;</td><td class="mdescRight">The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.  <a href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90">More...</a><br /></td></tr>
-<tr class="separator:ga67ac12fee79073242cb216e07c9f1f90"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga2be2b9969d4df9ecce9b05deed273194"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194">tjBufSizeYUV2</a> (int width, int pad, int height, int subsamp)</td></tr>
-<tr class="memdesc:ga2be2b9969d4df9ecce9b05deed273194"><td class="mdescLeft">&#160;</td><td class="mdescRight">The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.  <a href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194">More...</a><br /></td></tr>
-<tr class="separator:ga2be2b9969d4df9ecce9b05deed273194"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gab4ab7b24f6e797d79abaaa670373961d"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d">tjPlaneSizeYUV</a> (int componentID, int width, int stride, int height, int subsamp)</td></tr>
-<tr class="memdesc:gab4ab7b24f6e797d79abaaa670373961d"><td class="mdescLeft">&#160;</td><td class="mdescRight">The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d">More...</a><br /></td></tr>
-<tr class="separator:gab4ab7b24f6e797d79abaaa670373961d"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga63fb66bb1e36c74008c4634360becbb1"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1">tjPlaneWidth</a> (int componentID, int width, int subsamp)</td></tr>
-<tr class="memdesc:ga63fb66bb1e36c74008c4634360becbb1"><td class="mdescLeft">&#160;</td><td class="mdescRight">The plane width of a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1">More...</a><br /></td></tr>
-<tr class="separator:ga63fb66bb1e36c74008c4634360becbb1"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga1a209696c6a80748f20e134b3c64789f"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f">tjPlaneHeight</a> (int componentID, int height, int subsamp)</td></tr>
-<tr class="memdesc:ga1a209696c6a80748f20e134b3c64789f"><td class="mdescLeft">&#160;</td><td class="mdescRight">The plane height of a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f">More...</a><br /></td></tr>
-<tr class="separator:ga1a209696c6a80748f20e134b3c64789f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gac519b922cdf446e97d0cdcba513636bf"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac519b922cdf446e97d0cdcba513636bf">tjEncodeYUV3</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)</td></tr>
-<tr class="memdesc:gac519b922cdf446e97d0cdcba513636bf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an RGB or grayscale image into a YUV planar image.  <a href="group___turbo_j_p_e_g.html#gac519b922cdf446e97d0cdcba513636bf">More...</a><br /></td></tr>
-<tr class="separator:gac519b922cdf446e97d0cdcba513636bf"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gae2d04c72457fe7f4d60cf78ab1b1feb1"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae2d04c72457fe7f4d60cf78ab1b1feb1">tjEncodeYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp, int flags)</td></tr>
-<tr class="memdesc:gae2d04c72457fe7f4d60cf78ab1b1feb1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an RGB or grayscale image into separate Y, U (Cb), and V (Cr) image planes.  <a href="group___turbo_j_p_e_g.html#gae2d04c72457fe7f4d60cf78ab1b1feb1">More...</a><br /></td></tr>
-<tr class="separator:gae2d04c72457fe7f4d60cf78ab1b1feb1"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga52300eac3f3d9ef4bab303bc244f62d3"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga52300eac3f3d9ef4bab303bc244f62d3">tjInitDecompress</a> (void)</td></tr>
-<tr class="memdesc:ga52300eac3f3d9ef4bab303bc244f62d3"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG decompressor instance.  <a href="group___turbo_j_p_e_g.html#ga52300eac3f3d9ef4bab303bc244f62d3">More...</a><br /></td></tr>
-<tr class="separator:ga52300eac3f3d9ef4bab303bc244f62d3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga0595681096bba7199cc6f3533cb25f77"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0595681096bba7199cc6f3533cb25f77">tjDecompressHeader3</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, int *jpegSubsamp, int *jpegColorspace)</td></tr>
-<tr class="memdesc:ga0595681096bba7199cc6f3533cb25f77"><td class="mdescLeft">&#160;</td><td class="mdescRight">Retrieve information about a JPEG image without decompressing it, or prime the decompressor with quantization and Huffman tables.  <a href="group___turbo_j_p_e_g.html#ga0595681096bba7199cc6f3533cb25f77">More...</a><br /></td></tr>
-<tr class="separator:ga0595681096bba7199cc6f3533cb25f77"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gac3854476006b10787bd128f7ede48057"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057">tjGetScalingFactors</a> (int *numscalingfactors)</td></tr>
-<tr class="memdesc:gac3854476006b10787bd128f7ede48057"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of TurboJPEG supports.  <a href="group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057">More...</a><br /></td></tr>
-<tr class="separator:gac3854476006b10787bd128f7ede48057"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gae9eccef8b682a48f43a9117c231ed013"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae9eccef8b682a48f43a9117c231ed013">tjDecompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:gae9eccef8b682a48f43a9117c231ed013"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to an RGB, grayscale, or CMYK image.  <a href="group___turbo_j_p_e_g.html#gae9eccef8b682a48f43a9117c231ed013">More...</a><br /></td></tr>
-<tr class="separator:gae9eccef8b682a48f43a9117c231ed013"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga04d1e839ff9a0860dd1475cff78d3364"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga04d1e839ff9a0860dd1475cff78d3364">tjDecompressToYUV2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pad, int height, int flags)</td></tr>
-<tr class="memdesc:ga04d1e839ff9a0860dd1475cff78d3364"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to a YUV planar image.  <a href="group___turbo_j_p_e_g.html#ga04d1e839ff9a0860dd1475cff78d3364">More...</a><br /></td></tr>
-<tr class="separator:ga04d1e839ff9a0860dd1475cff78d3364"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaa59f901a5258ada5bd0185ad59368540"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa59f901a5258ada5bd0185ad59368540">tjDecompressToYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes, int width, int *strides, int height, int flags)</td></tr>
-<tr class="memdesc:gaa59f901a5258ada5bd0185ad59368540"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image planes.  <a href="group___turbo_j_p_e_g.html#gaa59f901a5258ada5bd0185ad59368540">More...</a><br /></td></tr>
-<tr class="separator:gaa59f901a5258ada5bd0185ad59368540"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga70abbf38f77a26fd6da8813bef96f695"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga70abbf38f77a26fd6da8813bef96f695">tjDecodeYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int pad, int subsamp, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:ga70abbf38f77a26fd6da8813bef96f695"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decode a YUV planar image into an RGB or grayscale image.  <a href="group___turbo_j_p_e_g.html#ga70abbf38f77a26fd6da8813bef96f695">More...</a><br /></td></tr>
-<tr class="separator:ga70abbf38f77a26fd6da8813bef96f695"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga10e837c07fa9d25770565b237d3898d9"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga10e837c07fa9d25770565b237d3898d9">tjDecodeYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char **srcPlanes, const int *strides, int subsamp, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:ga10e837c07fa9d25770565b237d3898d9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decode a set of Y, U (Cb), and V (Cr) image planes into an RGB or grayscale image.  <a href="group___turbo_j_p_e_g.html#ga10e837c07fa9d25770565b237d3898d9">More...</a><br /></td></tr>
-<tr class="separator:ga10e837c07fa9d25770565b237d3898d9"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga928beff6ac248ceadf01089fc6b41957"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga928beff6ac248ceadf01089fc6b41957">tjInitTransform</a> (void)</td></tr>
-<tr class="memdesc:ga928beff6ac248ceadf01089fc6b41957"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a new TurboJPEG transformer instance.  <a href="group___turbo_j_p_e_g.html#ga928beff6ac248ceadf01089fc6b41957">More...</a><br /></td></tr>
-<tr class="separator:ga928beff6ac248ceadf01089fc6b41957"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga9cb8abf4cc91881e04a0329b2270be25"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25">tjTransform</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, <a class="el" href="structtjtransform.html">tjtransform</a> *transforms, int flags)</td></tr>
-<tr class="memdesc:ga9cb8abf4cc91881e04a0329b2270be25"><td class="mdescLeft">&#160;</td><td class="mdescRight">Losslessly transform a JPEG image into another JPEG image.  <a href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25">More...</a><br /></td></tr>
-<tr class="separator:ga9cb8abf4cc91881e04a0329b2270be25"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga75f355fa27225ba1a4ee392c852394d2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga75f355fa27225ba1a4ee392c852394d2">tjDestroy</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
-<tr class="memdesc:ga75f355fa27225ba1a4ee392c852394d2"><td class="mdescLeft">&#160;</td><td class="mdescRight">Destroy a TurboJPEG compressor, decompressor, or transformer instance.  <a href="group___turbo_j_p_e_g.html#ga75f355fa27225ba1a4ee392c852394d2">More...</a><br /></td></tr>
-<tr class="separator:ga75f355fa27225ba1a4ee392c852394d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaec627dd4c5f30b7a775a7aea3bec5d83"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83">tjAlloc</a> (int bytes)</td></tr>
-<tr class="memdesc:gaec627dd4c5f30b7a775a7aea3bec5d83"><td class="mdescLeft">&#160;</td><td class="mdescRight">Allocate an image buffer for use with TurboJPEG.  <a href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83">More...</a><br /></td></tr>
-<tr class="separator:gaec627dd4c5f30b7a775a7aea3bec5d83"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaffbd83c375e79f5db4b5c5d8ad4466e7"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7">tjLoadImage</a> (const char *filename, int *width, int align, int *height, int *pixelFormat, int flags)</td></tr>
-<tr class="memdesc:gaffbd83c375e79f5db4b5c5d8ad4466e7"><td class="mdescLeft">&#160;</td><td class="mdescRight">Load an uncompressed image from disk into memory.  <a href="group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7">More...</a><br /></td></tr>
-<tr class="separator:gaffbd83c375e79f5db4b5c5d8ad4466e7"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga6f445b22d8933ae4815b3370a538d879"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6f445b22d8933ae4815b3370a538d879">tjSaveImage</a> (const char *filename, unsigned char *buffer, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:ga6f445b22d8933ae4815b3370a538d879"><td class="mdescLeft">&#160;</td><td class="mdescRight">Save an uncompressed image from memory to disk.  <a href="group___turbo_j_p_e_g.html#ga6f445b22d8933ae4815b3370a538d879">More...</a><br /></td></tr>
-<tr class="separator:ga6f445b22d8933ae4815b3370a538d879"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaea863d2da0cdb609563aabdf9196514b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b">tjFree</a> (unsigned char *buffer)</td></tr>
-<tr class="memdesc:gaea863d2da0cdb609563aabdf9196514b"><td class="mdescLeft">&#160;</td><td class="mdescRight">Free an image buffer previously allocated by TurboJPEG.  <a href="group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b">More...</a><br /></td></tr>
-<tr class="separator:gaea863d2da0cdb609563aabdf9196514b"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga1ead8574f9f39fbafc6b497124e7aafa"><td class="memItemLeft" align="right" valign="top">DLLEXPORT char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa">tjGetErrorStr2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
-<tr class="memdesc:ga1ead8574f9f39fbafc6b497124e7aafa"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a descriptive error message explaining why the last command failed.  <a href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa">More...</a><br /></td></tr>
-<tr class="separator:ga1ead8574f9f39fbafc6b497124e7aafa"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga414feeffbf860ebd31c745df203de410"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410">tjGetErrorCode</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
-<tr class="memdesc:ga414feeffbf860ebd31c745df203de410"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a code indicating the severity of the last error.  <a href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410">More...</a><br /></td></tr>
-<tr class="separator:ga414feeffbf860ebd31c745df203de410"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga69c09d39f97ec30250ad3605ace7e5df"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga69c09d39f97ec30250ad3605ace7e5df">tj3Init</a> (int initType)</td></tr>
+<tr class="memdesc:ga69c09d39f97ec30250ad3605ace7e5df"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a new TurboJPEG instance.  <a href="group___turbo_j_p_e_g.html#ga69c09d39f97ec30250ad3605ace7e5df">More...</a><br /></td></tr>
+<tr class="separator:ga69c09d39f97ec30250ad3605ace7e5df"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaddf92640bfee3e8622218c713e77e7db"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaddf92640bfee3e8622218c713e77e7db">tj3Set</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, int param, int value)</td></tr>
+<tr class="memdesc:gaddf92640bfee3e8622218c713e77e7db"><td class="mdescLeft">&#160;</td><td class="mdescRight">Set the value of a parameter.  <a href="group___turbo_j_p_e_g.html#gaddf92640bfee3e8622218c713e77e7db">More...</a><br /></td></tr>
+<tr class="separator:gaddf92640bfee3e8622218c713e77e7db"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga34af9ba3183bdf0ec7c8f47bb9a4c84f"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga34af9ba3183bdf0ec7c8f47bb9a4c84f">tj3Get</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, int param)</td></tr>
+<tr class="memdesc:ga34af9ba3183bdf0ec7c8f47bb9a4c84f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Get the value of a parameter.  <a href="group___turbo_j_p_e_g.html#ga34af9ba3183bdf0ec7c8f47bb9a4c84f">More...</a><br /></td></tr>
+<tr class="separator:ga34af9ba3183bdf0ec7c8f47bb9a4c84f"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga2cc418a2dab709ad7f30f5b25905f138"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga2cc418a2dab709ad7f30f5b25905f138">tj3Compress8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize)</td></tr>
+<tr class="memdesc:ga2cc418a2dab709ad7f30f5b25905f138"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into an 8-bit-per-sample JPEG image.  <a href="group___turbo_j_p_e_g.html#ga2cc418a2dab709ad7f30f5b25905f138">More...</a><br /></td></tr>
+<tr class="separator:ga2cc418a2dab709ad7f30f5b25905f138"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga9a1968c384ec7abb6122830253ebf570"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga9a1968c384ec7abb6122830253ebf570">tj3Compress12</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const short *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize)</td></tr>
+<tr class="memdesc:ga9a1968c384ec7abb6122830253ebf570"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into a 12-bit-per-sample JPEG image.  <a href="group___turbo_j_p_e_g.html#ga9a1968c384ec7abb6122830253ebf570">More...</a><br /></td></tr>
+<tr class="separator:ga9a1968c384ec7abb6122830253ebf570"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga77901b71d0471784f318ada31ff4e7bd"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga77901b71d0471784f318ada31ff4e7bd">tj3Compress16</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned short *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize)</td></tr>
+<tr class="memdesc:ga77901b71d0471784f318ada31ff4e7bd"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into a 16-bit-per-sample lossless JPEG image.  <a href="group___turbo_j_p_e_g.html#ga77901b71d0471784f318ada31ff4e7bd">More...</a><br /></td></tr>
+<tr class="separator:ga77901b71d0471784f318ada31ff4e7bd"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga041c870d9c669eb3f385c78f4346c43f"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga041c870d9c669eb3f385c78f4346c43f">tj3CompressFromYUV8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int align, int height, unsigned char **jpegBuf, size_t *jpegSize)</td></tr>
+<tr class="memdesc:ga041c870d9c669eb3f385c78f4346c43f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample JPEG image.  <a href="group___turbo_j_p_e_g.html#ga041c870d9c669eb3f385c78f4346c43f">More...</a><br /></td></tr>
+<tr class="separator:ga041c870d9c669eb3f385c78f4346c43f"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gac9f5ace3e73805b476c95dda9f8d0cd0"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac9f5ace3e73805b476c95dda9f8d0cd0">tj3CompressFromYUVPlanes8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *const *srcPlanes, int width, const int *strides, int height, unsigned char **jpegBuf, size_t *jpegSize)</td></tr>
+<tr class="memdesc:gac9f5ace3e73805b476c95dda9f8d0cd0"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into an 8-bit-per-sample JPEG image.  <a href="group___turbo_j_p_e_g.html#gac9f5ace3e73805b476c95dda9f8d0cd0">More...</a><br /></td></tr>
+<tr class="separator:gac9f5ace3e73805b476c95dda9f8d0cd0"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gac6285e58e35a35d871d7162ec5a929c4"><td class="memItemLeft" align="right" valign="top">DLLEXPORT size_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4">tj3JPEGBufSize</a> (int width, int height, int jpegSubsamp)</td></tr>
+<tr class="memdesc:gac6285e58e35a35d871d7162ec5a929c4"><td class="mdescLeft">&#160;</td><td class="mdescRight">The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.  <a href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4">More...</a><br /></td></tr>
+<tr class="separator:gac6285e58e35a35d871d7162ec5a929c4"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaaebaa16973a0f550a66eca5765ed0546"><td class="memItemLeft" align="right" valign="top">DLLEXPORT size_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546">tj3YUVBufSize</a> (int width, int align, int height, int subsamp)</td></tr>
+<tr class="memdesc:gaaebaa16973a0f550a66eca5765ed0546"><td class="mdescLeft">&#160;</td><td class="mdescRight">The size of the buffer (in bytes) required to hold a unified planar YUV image with the given parameters.  <a href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546">More...</a><br /></td></tr>
+<tr class="separator:gaaebaa16973a0f550a66eca5765ed0546"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gacc19d265edce76b46146f59579f9438d"><td class="memItemLeft" align="right" valign="top">DLLEXPORT size_t&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d">tj3YUVPlaneSize</a> (int componentID, int width, int stride, int height, int subsamp)</td></tr>
+<tr class="memdesc:gacc19d265edce76b46146f59579f9438d"><td class="mdescLeft">&#160;</td><td class="mdescRight">The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d">More...</a><br /></td></tr>
+<tr class="separator:gacc19d265edce76b46146f59579f9438d"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gac99d1933ede1d59fcada9a826e88eb2d"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gac99d1933ede1d59fcada9a826e88eb2d">tj3YUVPlaneWidth</a> (int componentID, int width, int subsamp)</td></tr>
+<tr class="memdesc:gac99d1933ede1d59fcada9a826e88eb2d"><td class="mdescLeft">&#160;</td><td class="mdescRight">The plane width of a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#gac99d1933ede1d59fcada9a826e88eb2d">More...</a><br /></td></tr>
+<tr class="separator:gac99d1933ede1d59fcada9a826e88eb2d"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga969767ec8180cc3edd99cf507f87299b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga969767ec8180cc3edd99cf507f87299b">tj3YUVPlaneHeight</a> (int componentID, int height, int subsamp)</td></tr>
+<tr class="memdesc:ga969767ec8180cc3edd99cf507f87299b"><td class="mdescLeft">&#160;</td><td class="mdescRight">The plane height of a YUV image plane with the given parameters.  <a href="group___turbo_j_p_e_g.html#ga969767ec8180cc3edd99cf507f87299b">More...</a><br /></td></tr>
+<tr class="separator:ga969767ec8180cc3edd99cf507f87299b"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga2a8d50f130bde10f0a04030f8cc59936"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga2a8d50f130bde10f0a04030f8cc59936">tj3EncodeYUV8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, int align)</td></tr>
+<tr class="memdesc:ga2a8d50f130bde10f0a04030f8cc59936"><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into an 8-bit-per-sample unified planar YUV image.  <a href="group___turbo_j_p_e_g.html#ga2a8d50f130bde10f0a04030f8cc59936">More...</a><br /></td></tr>
+<tr class="separator:ga2a8d50f130bde10f0a04030f8cc59936"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gae2e9df38790e9bddc249d04cb158a4cf"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae2e9df38790e9bddc249d04cb158a4cf">tj3EncodeYUVPlanes8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes, int *strides)</td></tr>
+<tr class="memdesc:gae2e9df38790e9bddc249d04cb158a4cf"><td class="mdescLeft">&#160;</td><td class="mdescRight">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.  <a href="group___turbo_j_p_e_g.html#gae2e9df38790e9bddc249d04cb158a4cf">More...</a><br /></td></tr>
+<tr class="separator:gae2e9df38790e9bddc249d04cb158a4cf"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga96d2c4b3432f9d88ad14758ae240b8d1"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga96d2c4b3432f9d88ad14758ae240b8d1">tj3DecompressHeader</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize)</td></tr>
+<tr class="memdesc:ga96d2c4b3432f9d88ad14758ae240b8d1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Retrieve information about a JPEG image without decompressing it, or prime the decompressor with quantization and Huffman tables.  <a href="group___turbo_j_p_e_g.html#ga96d2c4b3432f9d88ad14758ae240b8d1">More...</a><br /></td></tr>
+<tr class="separator:ga96d2c4b3432f9d88ad14758ae240b8d1"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga74397f8e0587d4233182c72f085aaf04"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga74397f8e0587d4233182c72f085aaf04">tj3GetScalingFactors</a> (int *numScalingFactors)</td></tr>
+<tr class="memdesc:ga74397f8e0587d4233182c72f085aaf04"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a list of fractional scaling factors that the JPEG decompressor supports.  <a href="group___turbo_j_p_e_g.html#ga74397f8e0587d4233182c72f085aaf04">More...</a><br /></td></tr>
+<tr class="separator:ga74397f8e0587d4233182c72f085aaf04"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga89da17ee1e43ff423382cbc145803c75"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75">tj3SetScalingFactor</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> scalingFactor)</td></tr>
+<tr class="memdesc:ga89da17ee1e43ff423382cbc145803c75"><td class="mdescLeft">&#160;</td><td class="mdescRight">Set the scaling factor for subsequent lossy decompression operations.  <a href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75">More...</a><br /></td></tr>
+<tr class="separator:ga89da17ee1e43ff423382cbc145803c75"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa49c7bd4c9431667a043cfc93388ba1c"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c">tj3SetCroppingRegion</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, <a class="el" href="structtjregion.html">tjregion</a> croppingRegion)</td></tr>
+<tr class="memdesc:gaa49c7bd4c9431667a043cfc93388ba1c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.  <a href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c">More...</a><br /></td></tr>
+<tr class="separator:gaa49c7bd4c9431667a043cfc93388ba1c"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga1169c7c1a26ec18c9e6122cb8ae64013"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1169c7c1a26ec18c9e6122cb8ae64013">tj3Decompress8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, unsigned char *dstBuf, int pitch, int pixelFormat)</td></tr>
+<tr class="memdesc:ga1169c7c1a26ec18c9e6122cb8ae64013"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK image.  <a href="group___turbo_j_p_e_g.html#ga1169c7c1a26ec18c9e6122cb8ae64013">More...</a><br /></td></tr>
+<tr class="separator:ga1169c7c1a26ec18c9e6122cb8ae64013"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga39b848f01781ad74a5b3941c012b6199"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga39b848f01781ad74a5b3941c012b6199">tj3Decompress12</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, short *dstBuf, int pitch, int pixelFormat)</td></tr>
+<tr class="memdesc:ga39b848f01781ad74a5b3941c012b6199"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a 12-bit-per-sample JPEG image into a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image.  <a href="group___turbo_j_p_e_g.html#ga39b848f01781ad74a5b3941c012b6199">More...</a><br /></td></tr>
+<tr class="separator:ga39b848f01781ad74a5b3941c012b6199"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa074e63f9beb0b3ff42b833a4049df6e"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa074e63f9beb0b3ff42b833a4049df6e">tj3Decompress16</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, unsigned short *dstBuf, int pitch, int pixelFormat)</td></tr>
+<tr class="memdesc:gaa074e63f9beb0b3ff42b833a4049df6e"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a 16-bit-per-sample lossless JPEG image into a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image.  <a href="group___turbo_j_p_e_g.html#gaa074e63f9beb0b3ff42b833a4049df6e">More...</a><br /></td></tr>
+<tr class="separator:gaa074e63f9beb0b3ff42b833a4049df6e"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga1e6bf6a19fec3f9fa7534348879d8320"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1e6bf6a19fec3f9fa7534348879d8320">tj3DecompressToYUV8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, unsigned char *dstBuf, int align)</td></tr>
+<tr class="memdesc:ga1e6bf6a19fec3f9fa7534348879d8320"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample unified planar YUV image.  <a href="group___turbo_j_p_e_g.html#ga1e6bf6a19fec3f9fa7534348879d8320">More...</a><br /></td></tr>
+<tr class="separator:ga1e6bf6a19fec3f9fa7534348879d8320"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga934373482dbbf257f2280505b6ff4fb5"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga934373482dbbf257f2280505b6ff4fb5">tj3DecompressToYUVPlanes8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, unsigned char **dstPlanes, int *strides)</td></tr>
+<tr class="memdesc:ga934373482dbbf257f2280505b6ff4fb5"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress an 8-bit-per-sample JPEG image into separate 8-bit-per-sample Y, U (Cb), and V (Cr) image planes.  <a href="group___turbo_j_p_e_g.html#ga934373482dbbf257f2280505b6ff4fb5">More...</a><br /></td></tr>
+<tr class="separator:ga934373482dbbf257f2280505b6ff4fb5"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa1eb574f38b1c1de43a6c7aafcf68d8c"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa1eb574f38b1c1de43a6c7aafcf68d8c">tj3DecodeYUV8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *srcBuf, int align, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat)</td></tr>
+<tr class="memdesc:gaa1eb574f38b1c1de43a6c7aafcf68d8c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decode an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample packed-pixel RGB or grayscale image.  <a href="group___turbo_j_p_e_g.html#gaa1eb574f38b1c1de43a6c7aafcf68d8c">More...</a><br /></td></tr>
+<tr class="separator:gaa1eb574f38b1c1de43a6c7aafcf68d8c"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gad366f1915f82c1ad4e7e37ebe073ca89"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad366f1915f82c1ad4e7e37ebe073ca89">tj3DecodeYUVPlanes8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *const *srcPlanes, const int *strides, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat)</td></tr>
+<tr class="memdesc:gad366f1915f82c1ad4e7e37ebe073ca89"><td class="mdescLeft">&#160;</td><td class="mdescRight">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.  <a href="group___turbo_j_p_e_g.html#gad366f1915f82c1ad4e7e37ebe073ca89">More...</a><br /></td></tr>
+<tr class="separator:gad366f1915f82c1ad4e7e37ebe073ca89"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaff23ba1dcabed456794b844791613920"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920">tj3Transform</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const unsigned char *jpegBuf, size_t jpegSize, int n, unsigned char **dstBufs, size_t *dstSizes, const <a class="el" href="structtjtransform.html">tjtransform</a> *transforms)</td></tr>
+<tr class="memdesc:gaff23ba1dcabed456794b844791613920"><td class="mdescLeft">&#160;</td><td class="mdescRight">Losslessly transform a JPEG image into another JPEG image.  <a href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920">More...</a><br /></td></tr>
+<tr class="separator:gaff23ba1dcabed456794b844791613920"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga53fbadf4560e95a65b8f5ab81703fe82"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga53fbadf4560e95a65b8f5ab81703fe82">tj3Destroy</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
+<tr class="memdesc:ga53fbadf4560e95a65b8f5ab81703fe82"><td class="mdescLeft">&#160;</td><td class="mdescRight">Destroy a TurboJPEG instance.  <a href="group___turbo_j_p_e_g.html#ga53fbadf4560e95a65b8f5ab81703fe82">More...</a><br /></td></tr>
+<tr class="separator:ga53fbadf4560e95a65b8f5ab81703fe82"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gab40a0b231122f536e503e3394569a68d"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d">tj3Alloc</a> (size_t bytes)</td></tr>
+<tr class="memdesc:gab40a0b231122f536e503e3394569a68d"><td class="mdescLeft">&#160;</td><td class="mdescRight">Allocate a byte buffer for use with TurboJPEG.  <a href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d">More...</a><br /></td></tr>
+<tr class="separator:gab40a0b231122f536e503e3394569a68d"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga565aaae7be3f8ca9099b56655c893251"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251">tj3LoadImage8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, int *width, int align, int *height, int *pixelFormat)</td></tr>
+<tr class="memdesc:ga565aaae7be3f8ca9099b56655c893251"><td class="mdescLeft">&#160;</td><td class="mdescRight">Load an 8-bit-per-sample packed-pixel image from disk into memory.  <a href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251">More...</a><br /></td></tr>
+<tr class="separator:ga565aaae7be3f8ca9099b56655c893251"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga1f03c26892a26d4ce077ed6a4ac40e8f"><td class="memItemLeft" align="right" valign="top">DLLEXPORT short *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga1f03c26892a26d4ce077ed6a4ac40e8f">tj3LoadImage12</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, int *width, int align, int *height, int *pixelFormat)</td></tr>
+<tr class="memdesc:ga1f03c26892a26d4ce077ed6a4ac40e8f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Load a 12-bit-per-sample packed-pixel image from disk into memory.  <a href="group___turbo_j_p_e_g.html#ga1f03c26892a26d4ce077ed6a4ac40e8f">More...</a><br /></td></tr>
+<tr class="separator:ga1f03c26892a26d4ce077ed6a4ac40e8f"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga638aeba63e0ccb89d472fdbf34224cfc"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned short *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga638aeba63e0ccb89d472fdbf34224cfc">tj3LoadImage16</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, int *width, int align, int *height, int *pixelFormat)</td></tr>
+<tr class="memdesc:ga638aeba63e0ccb89d472fdbf34224cfc"><td class="mdescLeft">&#160;</td><td class="mdescRight">Load a 16-bit-per-sample packed-pixel image from disk into memory.  <a href="group___turbo_j_p_e_g.html#ga638aeba63e0ccb89d472fdbf34224cfc">More...</a><br /></td></tr>
+<tr class="separator:ga638aeba63e0ccb89d472fdbf34224cfc"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaa4ec838988e469cc15618e4690cc8722"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722">tj3SaveImage8</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, const unsigned char *buffer, int width, int pitch, int height, int pixelFormat)</td></tr>
+<tr class="memdesc:gaa4ec838988e469cc15618e4690cc8722"><td class="mdescLeft">&#160;</td><td class="mdescRight">Save an 8-bit-per-sample packed-pixel image from memory to disk.  <a href="group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722">More...</a><br /></td></tr>
+<tr class="separator:gaa4ec838988e469cc15618e4690cc8722"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga7c64b5106d04267a46aad85f9714ad90"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7c64b5106d04267a46aad85f9714ad90">tj3SaveImage12</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, const short *buffer, int width, int pitch, int height, int pixelFormat)</td></tr>
+<tr class="memdesc:ga7c64b5106d04267a46aad85f9714ad90"><td class="mdescLeft">&#160;</td><td class="mdescRight">Save a 12-bit-per-sample packed-pixel image from memory to disk.  <a href="group___turbo_j_p_e_g.html#ga7c64b5106d04267a46aad85f9714ad90">More...</a><br /></td></tr>
+<tr class="separator:ga7c64b5106d04267a46aad85f9714ad90"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga0fd87851f4266aca24bf4594dd0c0e71"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0fd87851f4266aca24bf4594dd0c0e71">tj3SaveImage16</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, const char *filename, const unsigned short *buffer, int width, int pitch, int height, int pixelFormat)</td></tr>
+<tr class="memdesc:ga0fd87851f4266aca24bf4594dd0c0e71"><td class="mdescLeft">&#160;</td><td class="mdescRight">Save a 16-bit-per-sample packed-pixel image from memory to disk.  <a href="group___turbo_j_p_e_g.html#ga0fd87851f4266aca24bf4594dd0c0e71">More...</a><br /></td></tr>
+<tr class="separator:ga0fd87851f4266aca24bf4594dd0c0e71"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaddb84fb6c81769e9faa0f5a63b296606"><td class="memItemLeft" align="right" valign="top">DLLEXPORT void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606">tj3Free</a> (void *buffer)</td></tr>
+<tr class="memdesc:gaddb84fb6c81769e9faa0f5a63b296606"><td class="mdescLeft">&#160;</td><td class="mdescRight">Free a byte buffer previously allocated by TurboJPEG.  <a href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606">More...</a><br /></td></tr>
+<tr class="separator:gaddb84fb6c81769e9faa0f5a63b296606"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaf2aab0e6dbb3edc57646b0fec25e8bb2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT char *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2">tj3GetErrorStr</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
+<tr class="memdesc:gaf2aab0e6dbb3edc57646b0fec25e8bb2"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a descriptive error message explaining why the last command failed.  <a href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2">More...</a><br /></td></tr>
+<tr class="separator:gaf2aab0e6dbb3edc57646b0fec25e8bb2"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gab8c8279f1415fe425ff30dbbc56013bd"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd">tj3GetErrorCode</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
+<tr class="memdesc:gab8c8279f1415fe425ff30dbbc56013bd"><td class="mdescLeft">&#160;</td><td class="mdescRight">Returns a code indicating the severity of the last error.  <a href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd">More...</a><br /></td></tr>
+<tr class="separator:gab8c8279f1415fe425ff30dbbc56013bd"><td class="memSeparator" colspan="2">&#160;</td></tr>
 </table><table class="memberdecls">
 <tr class="heading"><td colspan="2"><h2 class="groupheader"><a name="var-members"></a>
 Variables</h2></td></tr>
@@ -330,20 +386,26 @@ Variables</h2></td></tr>
 <tr class="memdesc:gabd247bb9fecb393eca57366feb8327bf"><td class="mdescLeft">&#160;</td><td class="mdescRight">MCU block height (in pixels) for a given level of chrominance subsampling.  <a href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf">More...</a><br /></td></tr>
 <tr class="separator:gabd247bb9fecb393eca57366feb8327bf"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gadd9b446742ac8a3923f7992c7988fea8"><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8">tjRedOffset</a> [<a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a>]</td></tr>
-<tr class="memdesc:gadd9b446742ac8a3923f7992c7988fea8"><td class="mdescLeft">&#160;</td><td class="mdescRight">Red offset (in bytes) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8">More...</a><br /></td></tr>
+<tr class="memdesc:gadd9b446742ac8a3923f7992c7988fea8"><td class="mdescLeft">&#160;</td><td class="mdescRight">Red offset (in samples) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8">More...</a><br /></td></tr>
 <tr class="separator:gadd9b446742ac8a3923f7992c7988fea8"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga82d6e35da441112a411da41923c0ba2f"><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f">tjGreenOffset</a> [<a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a>]</td></tr>
-<tr class="memdesc:ga82d6e35da441112a411da41923c0ba2f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Green offset (in bytes) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f">More...</a><br /></td></tr>
+<tr class="memdesc:ga82d6e35da441112a411da41923c0ba2f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Green offset (in samples) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f">More...</a><br /></td></tr>
 <tr class="separator:ga82d6e35da441112a411da41923c0ba2f"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga84e2e35d3f08025f976ec1ec53693dea"><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea">tjBlueOffset</a> [<a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a>]</td></tr>
-<tr class="memdesc:ga84e2e35d3f08025f976ec1ec53693dea"><td class="mdescLeft">&#160;</td><td class="mdescRight">Blue offset (in bytes) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea">More...</a><br /></td></tr>
+<tr class="memdesc:ga84e2e35d3f08025f976ec1ec53693dea"><td class="mdescLeft">&#160;</td><td class="mdescRight">Blue offset (in samples) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea">More...</a><br /></td></tr>
 <tr class="separator:ga84e2e35d3f08025f976ec1ec53693dea"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga5af0ab065feefd526debf1e20c43e837"><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837">tjAlphaOffset</a> [<a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a>]</td></tr>
-<tr class="memdesc:ga5af0ab065feefd526debf1e20c43e837"><td class="mdescLeft">&#160;</td><td class="mdescRight">Alpha offset (in bytes) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837">More...</a><br /></td></tr>
+<tr class="memdesc:ga5af0ab065feefd526debf1e20c43e837"><td class="mdescLeft">&#160;</td><td class="mdescRight">Alpha offset (in samples) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837">More...</a><br /></td></tr>
 <tr class="separator:ga5af0ab065feefd526debf1e20c43e837"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gad77cf8fe5b2bfd3cb3f53098146abb4c"><td class="memItemLeft" align="right" valign="top">static const int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c">tjPixelSize</a> [<a class="el" href="group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e">TJ_NUMPF</a>]</td></tr>
-<tr class="memdesc:gad77cf8fe5b2bfd3cb3f53098146abb4c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Pixel size (in bytes) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c">More...</a><br /></td></tr>
+<tr class="memdesc:gad77cf8fe5b2bfd3cb3f53098146abb4c"><td class="mdescLeft">&#160;</td><td class="mdescRight">Pixel size (in samples) for a given pixel format.  <a href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c">More...</a><br /></td></tr>
 <tr class="separator:gad77cf8fe5b2bfd3cb3f53098146abb4c"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga6f192ad58a5a5802e145149d83c643bf"><td class="memItemLeft" align="right" valign="top">static const <a class="el" href="structtjregion.html">tjregion</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf">TJUNCROPPED</a></td></tr>
+<tr class="memdesc:ga6f192ad58a5a5802e145149d83c643bf"><td class="mdescLeft">&#160;</td><td class="mdescRight">A <a class="el" href="structtjregion.html" title="Cropping region.">tjregion</a> structure that specifies no cropping.  <a href="group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf">More...</a><br /></td></tr>
+<tr class="separator:ga6f192ad58a5a5802e145149d83c643bf"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga7880644a0849161ad20933536169ee19"><td class="memItemLeft" align="right" valign="top">static const <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7880644a0849161ad20933536169ee19">TJUNSCALED</a></td></tr>
+<tr class="memdesc:ga7880644a0849161ad20933536169ee19"><td class="mdescLeft">&#160;</td><td class="mdescRight">A <a class="el" href="structtjscalingfactor.html" title="Scaling factor.">tjscalingfactor</a> structure that specifies a scaling factor of 1/1 (no scaling)  <a href="group___turbo_j_p_e_g.html#ga7880644a0849161ad20933536169ee19">More...</a><br /></td></tr>
+<tr class="separator:ga7880644a0849161ad20933536169ee19"><td class="memSeparator" colspan="2">&#160;</td></tr>
 </table>
 <a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
 <p>TurboJPEG API. </p>
@@ -352,8 +414,8 @@ Variables</h2></td></tr>
 <h2><a class="anchor" id="autotoc_md0"></a>
 YUV Image Format Notes</h2>
 <p>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.</p>
-<p>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 (2 in the case of 4:2:0 and 4:2:2, 4 in the case of 4:1:1, 1 in the case of 4:4:4 or grayscale.) Similarly, the luminance plane height is the image height padded to the nearest multiple of the vertical subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4 or grayscale.) This is irrespective of any additional padding that may be specified as an argument to the various YUV functions. The chrominance plane width is equal to the luminance plane width divided by the horizontal subsampling factor, and the chrominance plane height is equal to the luminance plane height divided by the vertical subsampling factor.</p>
-<p>For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is used, then the luminance plane would be 36 x 35 bytes, and each of the chrominance planes would be 18 x 35 bytes. If you specify a line padding of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and each of the chrominance planes would be 20 x 35 bytes. </p>
+<p>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.</p>
+<p>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. </p>
 <h2 class="groupheader">Macro Definition Documentation</h2>
 <a id="ga39f57a6fb02d9cf32e7b6890099b5a71"></a>
 <h2 class="memtitle"><span class="permalink"><a href="#ga39f57a6fb02d9cf32e7b6890099b5a71">&#9670;&nbsp;</a></span>TJ_NUMCS</h2>
@@ -387,206 +449,83 @@ YUV Image Format Notes</h2>
 
 </div>
 </div>
-<a id="ga7010a4402f54a45ba822ad8675a4655e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga7010a4402f54a45ba822ad8675a4655e">&#9670;&nbsp;</a></span>TJ_NUMPF</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJ_NUMPF</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>The number of pixel formats. </p>
-
-</div>
-</div>
-<a id="ga5ef3d169162ce77ce348e292a0b7477c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga5ef3d169162ce77ce348e292a0b7477c">&#9670;&nbsp;</a></span>TJ_NUMSAMP</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJ_NUMSAMP</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>The number of chrominance subsampling options. </p>
-
-</div>
-</div>
-<a id="ga0f6dbd18adf38b7d46ac547f0f4d562c"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga0f6dbd18adf38b7d46ac547f0f4d562c">&#9670;&nbsp;</a></span>TJ_NUMXOP</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJ_NUMXOP</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>The number of transform operations. </p>
-
-</div>
-</div>
-<a id="gacb233cfd722d66d1ccbf48a7de81f0e0"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gacb233cfd722d66d1ccbf48a7de81f0e0">&#9670;&nbsp;</a></span>TJFLAG_ACCURATEDCT</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJFLAG_ACCURATEDCT</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>Use the most accurate DCT/IDCT algorithm available in the underlying codec. </p>
-<p>The default if this flag is not specified is implementation-specific. For example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast algorithm by default when compressing, because this has been shown to have only a very slight effect on accuracy, but it uses the accurate algorithm when decompressing, because this has been shown to have a larger effect. </p>
-
-</div>
-</div>
-<a id="ga72ecf4ebe6eb702d3c6f5ca27455e1ec"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">&#9670;&nbsp;</a></span>TJFLAG_BOTTOMUP</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJFLAG_BOTTOMUP</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>The uncompressed source/destination image is stored in bottom-up (Windows, OpenGL) order, not top-down (X11) order. </p>
-
-</div>
-</div>
-<a id="gaabce235db80d3f698b27f36cbd453da2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gaabce235db80d3f698b27f36cbd453da2">&#9670;&nbsp;</a></span>TJFLAG_FASTDCT</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJFLAG_FASTDCT</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>Use the fastest DCT/IDCT algorithm available in the underlying codec. </p>
-<p>The default if this flag is not specified is implementation-specific. For example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast algorithm by default when compressing, because this has been shown to have only a very slight effect on accuracy, but it uses the accurate algorithm when decompressing, because this has been shown to have a larger effect. </p>
-
-</div>
-</div>
-<a id="ga4ee4506c81177a06f77e2504a22efd2d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga4ee4506c81177a06f77e2504a22efd2d">&#9670;&nbsp;</a></span>TJFLAG_FASTUPSAMPLE</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
-        <tr>
-          <td class="memname">#define TJFLAG_FASTUPSAMPLE</td>
-        </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>When decompressing an image that was compressed using chrominance subsampling, use the fastest chrominance upsampling algorithm available in the underlying codec. </p>
-<p>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. </p>
-
-</div>
-</div>
-<a id="ga163e6482dc5096831feef9c79ff3f805"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga163e6482dc5096831feef9c79ff3f805">&#9670;&nbsp;</a></span>TJFLAG_LIMITSCANS</h2>
+<a id="ga5e0e8c784295c636f0bf8dab93c4bddf"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga5e0e8c784295c636f0bf8dab93c4bddf">&#9670;&nbsp;</a></span>TJ_NUMINIT</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">#define TJFLAG_LIMITSCANS</td>
+          <td class="memname">#define TJ_NUMINIT</td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Limit the number of progressive JPEG scans that the decompression and transform functions will process. </p>
-<p>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>. </p>
+<p>The number of initialization options. </p>
 
 </div>
 </div>
-<a id="ga8808d403c68b62aaa58a4c1e58e98963"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga8808d403c68b62aaa58a4c1e58e98963">&#9670;&nbsp;</a></span>TJFLAG_NOREALLOC</h2>
+<a id="gaa628be5db276fc3676dfba205d45d780"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa628be5db276fc3676dfba205d45d780">&#9670;&nbsp;</a></span>TJ_NUMPARAM</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">#define TJFLAG_NOREALLOC</td>
+          <td class="memname">#define TJ_NUMPARAM</td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Disable buffer (re)allocation. </p>
-<p>If passed to one of the JPEG compression or transform functions, this flag will cause those functions to generate an error if the JPEG image buffer is invalid or too small rather than attempting to allocate or reallocate that buffer. This reproduces the behavior of earlier versions of TurboJPEG. </p>
+<p>The number of parameters. </p>
 
 </div>
 </div>
-<a id="ga43b426750b46190a25d34a67ef76df1b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga43b426750b46190a25d34a67ef76df1b">&#9670;&nbsp;</a></span>TJFLAG_PROGRESSIVE</h2>
+<a id="ga7010a4402f54a45ba822ad8675a4655e"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga7010a4402f54a45ba822ad8675a4655e">&#9670;&nbsp;</a></span>TJ_NUMPF</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">#define TJFLAG_PROGRESSIVE</td>
+          <td class="memname">#define TJ_NUMPF</td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Use progressive entropy coding in JPEG images generated by the compression and transform functions. </p>
-<p>Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce compression and decompression performance considerably. </p>
+<p>The number of pixel formats. </p>
 
 </div>
 </div>
-<a id="ga519cfa4ef6c18d9e5b455fdf59306a3a"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga519cfa4ef6c18d9e5b455fdf59306a3a">&#9670;&nbsp;</a></span>TJFLAG_STOPONWARNING</h2>
+<a id="ga5ef3d169162ce77ce348e292a0b7477c"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga5ef3d169162ce77ce348e292a0b7477c">&#9670;&nbsp;</a></span>TJ_NUMSAMP</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">#define TJFLAG_STOPONWARNING</td>
+          <td class="memname">#define TJ_NUMSAMP</td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Immediately discontinue the current compression/decompression/transform operation if the underlying codec throws a warning (non-fatal error). </p>
-<p>The default behavior is to allow the operation to complete unless a fatal error is encountered. </p>
+<p>The number of chrominance subsampling options. </p>
 
 </div>
 </div>
-<a id="ga0aba955473315e405295d978f0c16511"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga0aba955473315e405295d978f0c16511">&#9670;&nbsp;</a></span>TJPAD</h2>
+<a id="ga0f6dbd18adf38b7d46ac547f0f4d562c"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga0f6dbd18adf38b7d46ac547f0f4d562c">&#9670;&nbsp;</a></span>TJ_NUMXOP</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">#define TJPAD</td>
-          <td>(</td>
-          <td class="paramtype">&#160;</td>
-          <td class="paramname">width</td><td>)</td>
-          <td></td>
+          <td class="memname">#define TJ_NUMXOP</td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Pad the given width to the nearest 32-bit boundary. </p>
+<p>The number of transform operations. </p>
 
 </div>
 </div>
@@ -621,6 +560,23 @@ YUV Image Format Notes</h2>
 
 </div>
 </div>
+<a id="gaecaaa3b7e2af812592c015d83207f010"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaecaaa3b7e2af812592c015d83207f010">&#9670;&nbsp;</a></span>TJXOPT_ARITHMETIC</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJXOPT_ARITHMETIC</td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>This option will enable arithmetic entropy coding in the JPEG image generated by this particular transform. </p>
+<p>Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding (the default), but it will reduce decompression performance considerably. Can be combined with <a class="el" href="group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026" title="This option will enable progressive entropy coding in the JPEG image generated by this particular tra...">TJXOPT_PROGRESSIVE</a>. </p>
+
+</div>
+</div>
 <a id="ga153b468cfb905d0de61706c838986fe8"></a>
 <h2 class="memtitle"><span class="permalink"><a href="#ga153b468cfb905d0de61706c838986fe8">&#9670;&nbsp;</a></span>TJXOPT_COPYNONE</h2>
 
@@ -633,7 +589,7 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> from copying any extra markers (including EXIF and ICC profile data) from the source image to the output image. </p>
+<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> from copying any extra markers (including EXIF and ICC profile data) from the source image to the destination image. </p>
 
 </div>
 </div>
@@ -650,7 +606,7 @@ YUV Image Format Notes</h2>
 </div><div class="memdoc">
 
 <p>This option will enable lossless cropping. </p>
-<p>See <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> for more information. </p>
+<p>See <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> for more information. </p>
 
 </div>
 </div>
@@ -666,7 +622,7 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will discard the color data in the input image and produce a grayscale output image. </p>
+<p>This option will discard the color data in the source image and produce a grayscale destination image. </p>
 
 </div>
 </div>
@@ -682,7 +638,25 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> 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.) </p>
+<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> from outputting a JPEG image for this particular transform. </p>
+<p>(This can be used in conjunction with a custom filter to capture the transformed DCT coefficients without transcoding them.) </p>
+
+</div>
+</div>
+<a id="ga6bedf37aa9e1122f3ec9f7302ca59117"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga6bedf37aa9e1122f3ec9f7302ca59117">&#9670;&nbsp;</a></span>TJXOPT_OPTIMIZE</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">#define TJXOPT_OPTIMIZE</td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>This option will enable optimized baseline entropy coding in the JPEG image generated by this particular transform. </p>
+<p>Optimized baseline entropy coding will improve compression slightly (generally 5% or less.) </p>
 
 </div>
 </div>
@@ -698,7 +672,7 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to return an error if the transform is not perfect. </p>
+<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> to return an error if the transform is not perfect. </p>
 <p>Lossless transforms operate on MCU blocks, whose size depends on the level of chrominance subsampling used (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a> and <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) 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. </p>
 
 </div>
@@ -715,8 +689,8 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will enable progressive entropy coding in the output image generated by this particular transform. </p>
-<p>Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce compression and decompression performance considerably. </p>
+<p>This option will enable progressive entropy coding in the JPEG image generated by this particular transform. </p>
+<p>Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce decompression performance considerably. Can be combined with <a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010" title="This option will enable arithmetic entropy coding in the JPEG image generated by this particular tran...">TJXOPT_ARITHMETIC</a>. Implies <a class="el" href="group___turbo_j_p_e_g.html#ga6bedf37aa9e1122f3ec9f7302ca59117" title="This option will enable optimized baseline entropy coding in the JPEG image generated by this particu...">TJXOPT_OPTIMIZE</a> unless <a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010" title="This option will enable arithmetic entropy coding in the JPEG image generated by this particular tran...">TJXOPT_ARITHMETIC</a> is also specified. </p>
 
 </div>
 </div>
@@ -732,7 +706,7 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to discard any partial MCU blocks that cannot be transformed. </p>
+<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> to discard any partial MCU blocks that cannot be transformed. </p>
 
 </div>
 </div>
@@ -785,19 +759,19 @@ YUV Image Format Notes</h2>
 <p>JPEG colorspaces. </p>
 <table class="fieldtable">
 <tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555"></a>TJCS_RGB&#160;</td><td class="fielddoc"><p>RGB colorspace. </p>
-<p>When compressing the JPEG image, the R, G, and B components in the source image are reordered into image planes, but no colorspace conversion or subsampling is performed. RGB JPEG images can be decompressed to any of the extended RGB pixel formats or grayscale, but they cannot be decompressed to YUV images. </p>
+<p>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 compressed from and decompressed to packed-pixel images with any of the extended RGB or grayscale pixel formats, but they cannot be compressed from or decompressed to planar YUV images. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75"></a>TJCS_YCbCr&#160;</td><td class="fielddoc"><p>YCbCr colorspace. </p>
-<p>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 &amp; 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 &amp; white and color televisions, but JPEG images use YCbCr primarily because it allows the color data to be optionally subsampled for the purposes of reducing bandwidth or disk space. YCbCr is the most common JPEG colorspace, and YCbCr JPEG images can be compressed from and decompressed to any of the extended RGB pixel formats or grayscale, or they can be decompressed to YUV planar images. </p>
+<p>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 &amp; 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 &amp; 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. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a"></a>TJCS_GRAY&#160;</td><td class="fielddoc"><p>Grayscale colorspace. </p>
-<p>The JPEG image retains only the luminance data (Y component), and any color data from the source image is discarded. Grayscale JPEG images can be compressed from and decompressed to any of the extended RGB pixel formats or grayscale, or they can be decompressed to YUV planar images. </p>
+<p>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. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53"></a>TJCS_CMYK&#160;</td><td class="fielddoc"><p>CMYK colorspace. </p>
-<p>When compressing the JPEG image, the C, M, Y, and K components in the source image are reordered into image planes, but no colorspace conversion or subsampling is performed. CMYK JPEG images can only be decompressed to CMYK pixels. </p>
+<p>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 compressed from and decompressed to packed-pixel images with the CMYK pixel format. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e"></a>TJCS_YCCK&#160;</td><td class="fielddoc"><p>YCCK colorspace. </p>
-<p>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 CMYK pixels. </p>
+<p>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. </p>
 </td></tr>
 </table>
 
@@ -817,7 +791,7 @@ YUV Image Format Notes</h2>
 
 <p>Error codes. </p>
 <table class="fieldtable">
-<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59"></a>TJERR_WARNING&#160;</td><td class="fielddoc"><p>The error was non-fatal and recoverable, but the image may still be corrupt. </p>
+<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59"></a>TJERR_WARNING&#160;</td><td class="fielddoc"><p>The error was non-fatal and recoverable, but the destination image may still be corrupt. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a"></a>TJERR_FATAL&#160;</td><td class="fielddoc"><p>The error was fatal and non-recoverable. </p>
 </td></tr>
@@ -825,6 +799,208 @@ YUV Image Format Notes</h2>
 
 </div>
 </div>
+<a id="ga3850bbee1313e752e667b4eb08b1e086"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga3850bbee1313e752e667b4eb08b1e086">&#9670;&nbsp;</a></span>TJINIT</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">enum <a class="el" href="group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086">TJINIT</a></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Initialization options. </p>
+<table class="fieldtable">
+<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="gga3850bbee1313e752e667b4eb08b1e086aa45ac279e3dc6ffabc4b0f45864da796"></a>TJINIT_COMPRESS&#160;</td><td class="fielddoc"><p>Initialize the TurboJPEG instance for compression. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="gga3850bbee1313e752e667b4eb08b1e086a4b8ca1ef700699b71350700bf95c2167"></a>TJINIT_DECOMPRESS&#160;</td><td class="fielddoc"><p>Initialize the TurboJPEG instance for decompression. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="gga3850bbee1313e752e667b4eb08b1e086a8d58a2a4c45b3e0cd349746544a6e0c2"></a>TJINIT_TRANSFORM&#160;</td><td class="fielddoc"><p>Initialize the TurboJPEG instance for lossless transformation (both compression and decompression.) </p>
+</td></tr>
+</table>
+
+</div>
+</div>
+<a id="gaa0f6be63ba78278299c9f5c12031fe82"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa0f6be63ba78278299c9f5c12031fe82">&#9670;&nbsp;</a></span>TJPARAM</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">enum <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">TJPARAM</a></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Parameters. </p>
+<table class="fieldtable">
+<tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a555e2212079fa49b30bcd2879c6c8ddb"></a>TJPARAM_STOPONWARNING&#160;</td><td class="fielddoc"><p>Error handling behavior. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> Allow the current compression/decompression/transform operation to complete unless a fatal error is encountered.</li>
+<li><code>1</code> Immediately discontinue the current compression/decompression/transform operation if a warning (non-fatal error) occurs. </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a924657172695ed6cb0b128219546fcce"></a>TJPARAM_BOTTOMUP&#160;</td><td class="fielddoc"><p>Row order in packed-pixel source/destination images. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> top-down (X11) order</li>
+<li><code>1</code> bottom-up (Windows, OpenGL) order </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b"></a>TJPARAM_NOREALLOC&#160;</td><td class="fielddoc"><p>JPEG destination buffer (re)allocation [compression, lossless transformation]. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> Attempt to allocate or reallocate the JPEG destination buffer as needed.</li>
+<li><code>1</code> Generate an error if the JPEG destination buffer is invalid or too small. </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a0467e8792621f2d817dc2af563d3186c"></a>TJPARAM_QUALITY&#160;</td><td class="fielddoc"><p>Perceptual quality of lossy JPEG images [compression only]. </p>
+<p><b>Value</b></p><ul>
+<li><code>1</code>-<code>100</code> (<code>1</code> = worst quality but best compression, <code>100</code> = best quality but worst compression) <em>[no default; must be explicitly specified]</em> </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a"></a>TJPARAM_SUBSAMP&#160;</td><td class="fielddoc"><p>Chrominance subsampling level. </p>
+<p>The JPEG or YUV image uses (decompression, decoding) or will use (lossy compression, encoding) the specified level of chrominance subsampling.</p>
+<p><b>Value</b></p><ul>
+<li>One of the <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">chrominance subsampling options</a> <em>[no default; must be explicitly specified for lossy compression, encoding, and decoding]</em> </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8"></a>TJPARAM_JPEGWIDTH&#160;</td><td class="fielddoc"><p>JPEG width (in pixels) [decompression only, read-only]. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f"></a>TJPARAM_JPEGHEIGHT&#160;</td><td class="fielddoc"><p>JPEG height (in pixels) [decompression only, read-only]. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a781db82741934e8cd008d308597c59d8"></a>TJPARAM_PRECISION&#160;</td><td class="fielddoc"><p>JPEG data precision (bits per sample) [decompression only, read-only]. </p>
+<p>The JPEG image uses the specified number of bits per sample.</p>
+<p><b>Value</b></p><ul>
+<li><code>8</code>, <code>12</code>, or <code>16</code></li>
+</ul>
+<p>12-bit data precision implies <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6" title="Optimized baseline entropy coding [lossy compression only].">TJPARAM_OPTIMIZE</a> unless <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7" title="Arithmetic entropy coding.">TJPARAM_ARITHMETIC</a> is set. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a46a10d46309514907d0c39fcd86c324c"></a>TJPARAM_COLORSPACE&#160;</td><td class="fielddoc"><p>JPEG colorspace. </p>
+<p>The JPEG image uses (decompression) or will use (lossy compression) the specified colorspace.</p>
+<p><b>Value</b></p><ul>
+<li>One of the <a class="el" href="group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720">JPEG colorspaces</a> <em>[default for lossy compression: automatically selected based on the subsampling level and pixel format]</em> </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a0e051ac106f7b7402b690a5daf4869c0"></a>TJPARAM_FASTUPSAMPLE&#160;</td><td class="fielddoc"><p>Chrominance upsampling algorithm [lossy decompression only]. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> Use smooth upsampling when decompressing a JPEG image that was compressed using chrominance subsampling. This creates a smooth transition between neighboring chrominance components in order to reduce upsampling artifacts in the decompressed image.</li>
+<li><code>1</code> Use the fastest chrominance upsampling algorithm available, which may combine upsampling with color conversion. </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a6914692ac6ec5567787d592b7563f627"></a>TJPARAM_FASTDCT&#160;</td><td class="fielddoc"><p>DCT/IDCT algorithm [lossy compression and decompression]. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> Use the most accurate DCT/IDCT algorithm available.</li>
+<li><code>1</code> Use the fastest DCT/IDCT algorithm available.</li>
+</ul>
+<p>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:</p><ul>
+<li>The "fast" and "accurate" DCT/IDCT algorithms perform similarly on modern x86/x86-64 CPUs that support AVX2 instructions.</li>
+<li>The "fast" algorithm is generally only about 5-15% faster than the "accurate" algorithm on other types of CPUs.</li>
+<li>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.</li>
+<li>The "fast" algorithm degrades and is not fully accelerated for JPEG quality levels above 97, so it will be slower than the "accurate" algorithm. </li>
+</ul>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6"></a>TJPARAM_OPTIMIZE&#160;</td><td class="fielddoc"><p>Optimized baseline entropy coding [lossy compression only]. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default]</em> The JPEG image will use the default Huffman tables.</li>
+<li><code>1</code> Optimal Huffman tables will be computed for the JPEG image. For lossless transformation, this can also be specified using <a class="el" href="group___turbo_j_p_e_g.html#ga6bedf37aa9e1122f3ec9f7302ca59117" title="This option will enable optimized baseline entropy coding in the JPEG image generated by this particu...">TJXOPT_OPTIMIZE</a>.</li>
+</ul>
+<p>Optimized baseline entropy coding will improve compression slightly (generally 5% or less), but it will reduce compression performance considerably. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f"></a>TJPARAM_PROGRESSIVE&#160;</td><td class="fielddoc"><p>Progressive entropy coding. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default for compression, lossless transformation]</em> The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) baseline entropy coding.</li>
+<li><code>1</code> The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) progressive entropy coding. For lossless transformation, this can also be specified using <a class="el" href="group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026" title="This option will enable progressive entropy coding in the JPEG image generated by this particular tra...">TJXOPT_PROGRESSIVE</a>.</li>
+</ul>
+<p>Progressive entropy coding will generally improve compression relative to baseline entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7" title="Arithmetic entropy coding.">TJPARAM_ARITHMETIC</a>. Implies <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6" title="Optimized baseline entropy coding [lossy compression only].">TJPARAM_OPTIMIZE</a> unless <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7" title="Arithmetic entropy coding.">TJPARAM_ARITHMETIC</a> is also set. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82ac478910e20ecf61b914f9824d80f8167"></a>TJPARAM_SCANLIMIT&#160;</td><td class="fielddoc"><p>Progressive JPEG scan limit for lossy JPEG images [decompression, lossless transformation]. </p>
+<p>Setting this parameter will cause the decompression and transform functions to return an error if the number of scans in a progressive JPEG image exceeds the specified limit. The primary purpose of this is to allow security-critical applications to guard against an exploit of the progressive JPEG format described in <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.</p>
+<p><b>Value</b></p><ul>
+<li>maximum number of progressive JPEG scans that the decompression and transform functions will process <em>[default: <code>0</code> (no limit)]</em></li>
+</ul>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f" title="Progressive entropy coding.">TJPARAM_PROGRESSIVE</a> </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7"></a>TJPARAM_ARITHMETIC&#160;</td><td class="fielddoc"><p>Arithmetic entropy coding. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default for compression, lossless transformation]</em> The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) Huffman entropy coding.</li>
+<li><code>1</code> The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) arithmetic entropy coding. For lossless transformation, this can also be specified using <a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010" title="This option will enable arithmetic entropy coding in the JPEG image generated by this particular tran...">TJXOPT_ARITHMETIC</a>.</li>
+</ul>
+<p>Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f" title="Progressive entropy coding.">TJPARAM_PROGRESSIVE</a>. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f"></a>TJPARAM_LOSSLESS&#160;</td><td class="fielddoc"><p>Lossless JPEG. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default for compression]</em> The JPEG image is (decompression) or will be (compression) lossy/DCT-based.</li>
+<li><code>1</code> The JPEG image is (decompression) or will be (compression) lossless/predictive.</li>
+</ul>
+<p>In most cases, compressing and decompressing lossless JPEG images is considerably slower than compressing and decompressing lossy JPEG images. Also note that the following features are not available with lossless JPEG images:</p><ul>
+<li>Colorspace conversion (lossless JPEG images always use <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555" title="RGB colorspace.">TJCS_RGB</a>, <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a" title="Grayscale colorspace.">TJCS_GRAY</a>, or <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53" title="CMYK colorspace.">TJCS_CMYK</a>, depending on the pixel format of the source image)</li>
+<li>Chrominance subsampling (lossless JPEG images always use <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3" title="4:4:4 chrominance subsampling (no chrominance subsampling).">TJSAMP_444</a>)</li>
+<li>JPEG quality selection</li>
+<li>DCT/IDCT algorithm selection</li>
+<li>Progressive entropy coding</li>
+<li>Arithmetic entropy coding</li>
+<li>Compression from/decompression to planar YUV images</li>
+<li>Decompression scaling</li>
+<li>Lossless transformation</li>
+</ul>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abcc997d40e5bec84817c12b76ef84159" title="Lossless JPEG predictor selection value (PSV)">TJPARAM_LOSSLESSPSV</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4a6c6f25764ecaf4231a36bff844e46a" title="Lossless JPEG point transform (Pt)">TJPARAM_LOSSLESSPT</a> </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82abcc997d40e5bec84817c12b76ef84159"></a>TJPARAM_LOSSLESSPSV&#160;</td><td class="fielddoc"><p>Lossless JPEG predictor selection value (PSV) </p>
+<p><b>Value</b></p><ul>
+<li><code>1</code>-<code>7</code> <em>[default for compression: <code>1</code>]</em></li>
+</ul>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f" title="Lossless JPEG.">TJPARAM_LOSSLESS</a> </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a4a6c6f25764ecaf4231a36bff844e46a"></a>TJPARAM_LOSSLESSPT&#160;</td><td class="fielddoc"><p>Lossless JPEG point transform (Pt) </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> through <em><b>precision</b></em> <em>- 1</em>, where <em><b>precision</b></em> is the JPEG data precision in bits <em>[default for compression: <code>0</code>]</em></li>
+</ul>
+<p>A point transform value of <code>0</code> 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.)</p>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f" title="Lossless JPEG.">TJPARAM_LOSSLESS</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a781db82741934e8cd008d308597c59d8" title="JPEG data precision (bits per sample) [decompression only, read-only].">TJPARAM_PRECISION</a> </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec"></a>TJPARAM_RESTARTBLOCKS&#160;</td><td class="fielddoc"><p>JPEG restart marker interval in MCU blocks (lossy) or samples (lossless) [compression only]. </p>
+<p>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.</p>
+<p><b>Value</b></p><ul>
+<li>the number of MCU blocks or samples between each restart marker <em>[default: <code>0</code> (no restart markers)]</em></li>
+</ul>
+<p>Setting this parameter to a non-zero value sets <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a714367585952fe5c863f0dba5bd37e5c" title="JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless) [compression only].">TJPARAM_RESTARTROWS</a> to 0. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a714367585952fe5c863f0dba5bd37e5c"></a>TJPARAM_RESTARTROWS&#160;</td><td class="fielddoc"><p>JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless) [compression only]. </p>
+<p>See <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec" title="JPEG restart marker interval in MCU blocks (lossy) or samples (lossless) [compression only].">TJPARAM_RESTARTBLOCKS</a> for a description of restart markers.</p>
+<p><b>Value</b></p><ul>
+<li>the number of MCU rows or sample rows between each restart marker <em>[default: <code>0</code> (no restart markers)]</em></li>
+</ul>
+<p>Setting this parameter to a non-zero value sets <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec" title="JPEG restart marker interval in MCU blocks (lossy) or samples (lossless) [compression only].">TJPARAM_RESTARTBLOCKS</a> to 0. </p>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a4de5c9d7cab5be806143a43c3b0e0877"></a>TJPARAM_XDENSITY&#160;</td><td class="fielddoc"><p>JPEG horizontal pixel density. </p>
+<p><b>Value</b></p><ul>
+<li>The JPEG image has (decompression) or will have (compression) the specified horizontal pixel density <em>[default for compression: <code>1</code>]</em>.</li>
+</ul>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251" title="Load an 8-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage8()</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722" title="Save an 8-bit-per-sample packed-pixel image from memory to disk.">tj3SaveImage8()</a> if the value of #TJPARAM_DENSITYUNIT is <code>2</code>.</p>
+<dl class="section see"><dt>See also</dt><dd>TJPARAM_DENSITYUNIT </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82abda48f2df7eb9b88e2b7621efb017eba"></a>TJPARAM_YDENSITY&#160;</td><td class="fielddoc"><p>JPEG vertical pixel density. </p>
+<p><b>Value</b></p><ul>
+<li>The JPEG image has (decompression) or will have (compression) the specified vertical pixel density <em>[default for compression: <code>1</code>]</em>.</li>
+</ul>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251" title="Load an 8-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage8()</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722" title="Save an 8-bit-per-sample packed-pixel image from memory to disk.">tj3SaveImage8()</a> if the value of #TJPARAM_DENSITYUNIT is <code>2</code>.</p>
+<dl class="section see"><dt>See also</dt><dd>TJPARAM_DENSITYUNIT </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="ggaa0f6be63ba78278299c9f5c12031fe82a4c045981bd8a303521a401dbbe1df208"></a>TJPARAM_DENSITYUNITS&#160;</td><td class="fielddoc"><p>JPEG pixel density units. </p>
+<p><b>Value</b></p><ul>
+<li><code>0</code> <em>[default for compression]</em> The pixel density of the JPEG image is expressed (decompression) or will be expressed (compression) in unknown units.</li>
+<li><code>1</code> The pixel density of the JPEG image is expressed (decompression) or will be expressed (compression) in units of pixels/inch.</li>
+<li><code>2</code> The pixel density of the JPEG image is expressed (decompression) or will be expressed (compression) in units of pixels/cm.</li>
+</ul>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251" title="Load an 8-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage8()</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722" title="Save an 8-bit-per-sample packed-pixel image from memory to disk.">tj3SaveImage8()</a> if the value is <code>2</code>.</p>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4de5c9d7cab5be806143a43c3b0e0877" title="JPEG horizontal pixel density.">TJPARAM_XDENSITY</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abda48f2df7eb9b88e2b7621efb017eba" title="JPEG vertical pixel density.">TJPARAM_YDENSITY</a> </dd></dl>
+</td></tr>
+</table>
+
+</div>
+</div>
 <a id="gac916144e26c3817ac514e64ae5d12e2a"></a>
 <h2 class="memtitle"><span class="permalink"><a href="#gac916144e26c3817ac514e64ae5d12e2a">&#9670;&nbsp;</a></span>TJPF</h2>
 
@@ -840,43 +1016,43 @@ YUV Image Format Notes</h2>
 <p>Pixel formats. </p>
 <table class="fieldtable">
 <tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c"></a>TJPF_RGB&#160;</td><td class="fielddoc"><p>RGB pixel format. </p>
-<p>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. </p>
+<p>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. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aab10624437fb8ef495a0b153e65749839"></a>TJPF_BGR&#160;</td><td class="fielddoc"><p>BGR pixel format. </p>
-<p>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. </p>
+<p>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. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01"></a>TJPF_RGBX&#160;</td><td class="fielddoc"><p>RGBX pixel format. </p>
-<p>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. </p>
+<p>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 and undefined when decompressing. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8"></a>TJPF_BGRX&#160;</td><td class="fielddoc"><p>BGRX pixel format. </p>
-<p>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. </p>
+<p>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 and undefined when decompressing. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af"></a>TJPF_XBGR&#160;</td><td class="fielddoc"><p>XBGR pixel format. </p>
-<p>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. </p>
+<p>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 and undefined when decompressing. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84"></a>TJPF_XRGB&#160;</td><td class="fielddoc"><p>XRGB pixel format. </p>
-<p>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. </p>
+<p>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 and undefined when decompressing. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a"></a>TJPF_GRAY&#160;</td><td class="fielddoc"><p>Grayscale pixel format. </p>
-<p>Each 1-byte pixel represents a luminance (brightness) level from 0 to 255. </p>
+<p>Each 1-sample pixel represents a luminance (brightness) level from 0 to the maximum sample value (255 for 8-bit samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12"></a>TJPF_RGBA&#160;</td><td class="fielddoc"><p>RGBA pixel format. </p>
-<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01">TJPF_RGBX</a>, except that when decompressing, the X component is guaranteed to be 0xFF, which can be interpreted as an opaque alpha channel. </p>
+<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01">TJPF_RGBX</a>, except that when decompressing, the X component is guaranteed to be equal to the maximum sample value, which can be interpreted as an opaque alpha channel. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4"></a>TJPF_BGRA&#160;</td><td class="fielddoc"><p>BGRA pixel format. </p>
-<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8">TJPF_BGRX</a>, except that when decompressing, the X component is guaranteed to be 0xFF, which can be interpreted as an opaque alpha channel. </p>
+<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8">TJPF_BGRX</a>, except that when decompressing, the X component is guaranteed to be equal to the maximum sample value, which can be interpreted as an opaque alpha channel. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081"></a>TJPF_ABGR&#160;</td><td class="fielddoc"><p>ABGR pixel format. </p>
-<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af">TJPF_XBGR</a>, except that when decompressing, the X component is guaranteed to be 0xFF, which can be interpreted as an opaque alpha channel. </p>
+<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af">TJPF_XBGR</a>, except that when decompressing, the X component is guaranteed to be equal to the maximum sample value, which can be interpreted as an opaque alpha channel. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c"></a>TJPF_ARGB&#160;</td><td class="fielddoc"><p>ARGB pixel format. </p>
-<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84">TJPF_XRGB</a>, except that when decompressing, the X component is guaranteed to be 0xFF, which can be interpreted as an opaque alpha channel. </p>
+<p>This is the same as <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84">TJPF_XRGB</a>, except that when decompressing, the X component is guaranteed to be equal to the maximum sample value, which can be interpreted as an opaque alpha channel. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b"></a>TJPF_CMYK&#160;</td><td class="fielddoc"><p>CMYK pixel format. </p>
-<p>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 CMYK pixels into a YCCK JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e" title="YCCK colorspace.">TJCS_YCCK</a>) and decompressing YCCK JPEG images into CMYK pixels. </p>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e" title="YCCK colorspace.">TJCS_YCCK</a>) and decompressing YCCK JPEG images into packed-pixel CMYK images. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed"></a>TJPF_UNKNOWN&#160;</td><td class="fielddoc"><p>Unknown pixel format. </p>
-<p>Currently this is only used by <a class="el" href="group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7" title="Load an uncompressed image from disk into memory.">tjLoadImage()</a>. </p>
+<p>Currently this is only used by <a class="el" href="group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251" title="Load an 8-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage8()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ga1f03c26892a26d4ce077ed6a4ac40e8f" title="Load a 12-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage12()</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga638aeba63e0ccb89d472fdbf34224cfc" title="Load a 16-bit-per-sample packed-pixel image from disk into memory.">tj3LoadImage16()</a>. </p>
 </td></tr>
 </table>
 
@@ -895,7 +1071,7 @@ YUV Image Format Notes</h2>
 </div><div class="memdoc">
 
 <p>Chrominance subsampling options. </p>
-<p>When pixels are converted from RGB to YCbCr (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75" title="YCbCr colorspace.">TJCS_YCbCr</a>) or from CMYK to YCCK (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e" title="YCCK colorspace.">TJCS_YCCK</a>) 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". </p>
+<p>When pixels are converted from RGB to YCbCr (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75" title="YCbCr colorspace.">TJCS_YCbCr</a>) or from CMYK to YCCK (see <a class="el" href="group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e" title="YCCK colorspace.">TJCS_YCCK</a>) 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". </p>
 <table class="fieldtable">
 <tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3"></a>TJSAMP_444&#160;</td><td class="fielddoc"><p>4:4:4 chrominance subsampling (no chrominance subsampling). </p>
 <p>The JPEG or YUV image will contain one chrominance component for every pixel in the source image. </p>
@@ -917,6 +1093,17 @@ YUV Image Format Notes</h2>
 <p>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.</p>
 <dl class="section note"><dt>Note</dt><dd>4:1:1 subsampling is not fully accelerated in libjpeg-turbo. </dd></dl>
 </td></tr>
+<tr><td class="fieldname"><a id="gga1d047060ea80bb9820d540bb928e9074a3351696e1dd34a083a35b6be8b90122d"></a>TJSAMP_441&#160;</td><td class="fielddoc"><p>4:4:1 chrominance subsampling. </p>
+<p>The JPEG or YUV image will contain one chrominance component for every 1x4 block of pixels in the source image. JPEG images compressed with 4:4: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:4:1 is better able to reproduce sharp vertical features.</p>
+<dl class="section note"><dt>Note</dt><dd>4:4:1 subsampling is not fully accelerated in libjpeg-turbo. </dd></dl>
+</td></tr>
+<tr><td class="fieldname"><a id="gga1d047060ea80bb9820d540bb928e9074ac124fa8f6cb41147e3d670dfbdfb7173"></a>TJSAMP_UNKNOWN&#160;</td><td class="fielddoc"><p>Unknown subsampling. </p>
+<p>The JPEG image uses an unusual type of chrominance subsampling. Such images can be decompressed into packed-pixel images, but they cannot be</p><ul>
+<li>decompressed into planar YUV images,</li>
+<li>losslessly transformed if <a class="el" href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2" title="This option will enable lossless cropping.">TJXOPT_CROP</a> is specified, or</li>
+<li>partially decompressed using a cropping region. </li>
+</ul>
+</td></tr>
 </table>
 
 </div>
@@ -933,52 +1120,52 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> </p>
+<p>Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a> </p>
 <table class="fieldtable">
 <tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27"></a>TJXOP_NONE&#160;</td><td class="fielddoc"><p>Do not transform the position of the image pixels. </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce"></a>TJXOP_HFLIP&#160;</td><td class="fielddoc"><p>Flip (mirror) image horizontally. </p>
-<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866a324eddfbec53b7e691f61e56929d0d5d"></a>TJXOP_VFLIP&#160;</td><td class="fielddoc"><p>Flip (mirror) image vertically. </p>
-<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866a31060aed199f886afdd417f80499c32d"></a>TJXOP_TRANSPOSE&#160;</td><td class="fielddoc"><p>Transpose image (flip/mirror along upper left to lower right axis.) This transform is always perfect. </p>
 </td></tr>
-<tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4"></a>TJXOP_TRANSVERSE&#160;</td><td class="fielddoc"><p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4"></a>TJXOP_TRANSVERSE&#160;</td><td class="fielddoc"><p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866a43b2bbb23bc4bd548422d43fbe9af128"></a>TJXOP_ROT90&#160;</td><td class="fielddoc"><p>Rotate image clockwise by 90 degrees. </p>
-<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the bottom edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866a140952eb8dd0300accfcc22726d69692"></a>TJXOP_ROT180&#160;</td><td class="fielddoc"><p>Rotate image 180 degrees. </p>
-<p>This transform is imperfect if there are any partial MCU blocks in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<p>This transform is imperfect if there are any partial MCU blocks in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 <tr><td class="fieldname"><a id="gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08"></a>TJXOP_ROT270&#160;</td><td class="fielddoc"><p>Rotate image counter-clockwise by 90 degrees. </p>
-<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tjTransform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
+<p>This transform is imperfect if there are any partial MCU blocks on the right edge (see <a class="el" href="group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00" title="This option will cause tj3Transform() to return an error if the transform is not perfect.">TJXOPT_PERFECT</a>.) </p>
 </td></tr>
 </table>
 
 </div>
 </div>
 <h2 class="groupheader">Function Documentation</h2>
-<a id="gaec627dd4c5f30b7a775a7aea3bec5d83"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gaec627dd4c5f30b7a775a7aea3bec5d83">&#9670;&nbsp;</a></span>tjAlloc()</h2>
+<a id="gab40a0b231122f536e503e3394569a68d"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gab40a0b231122f536e503e3394569a68d">&#9670;&nbsp;</a></span>tj3Alloc()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT unsigned char* tjAlloc </td>
+          <td class="memname">DLLEXPORT void* tj3Alloc </td>
           <td>(</td>
-          <td class="paramtype">int&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>bytes</em></td><td>)</td>
           <td></td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Allocate an image buffer for use with TurboJPEG. </p>
-<p>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 <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>.)</p>
+<p>Allocate a byte buffer for use with TurboJPEG. </p>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>.)</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
     <tr><td class="paramname">bytes</td><td>the number of bytes to allocate</td></tr>
@@ -986,19 +1173,31 @@ YUV Image Format Notes</h2>
   </dd>
 </dl>
 <dl class="section return"><dt>Returns</dt><dd>a pointer to a newly-allocated buffer with the specified number of bytes.</dd></dl>
-<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b" title="Free an image buffer previously allocated by TurboJPEG.">tjFree()</a> </dd></dl>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606" title="Free a byte buffer previously allocated by TurboJPEG.">tj3Free()</a> </dd></dl>
 
 </div>
 </div>
-<a id="ga67ac12fee79073242cb216e07c9f1f90"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga67ac12fee79073242cb216e07c9f1f90">&#9670;&nbsp;</a></span>tjBufSize()</h2>
+<a id="ga9a1968c384ec7abb6122830253ebf570"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga9a1968c384ec7abb6122830253ebf570">&#9670;&nbsp;</a></span>tj3Compress12()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT unsigned long tjBufSize </td>
+          <td class="memname">DLLEXPORT int tj3Compress12 </td>
           <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const short *&#160;</td>
+          <td class="paramname"><em>srcBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
           <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>width</em>, </td>
         </tr>
@@ -1006,13 +1205,31 @@ YUV Image Format Notes</h2>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>height</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>jpegSubsamp</em>&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1022,29 +1239,50 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters. </p>
-<p>The number of bytes returned by this function is larger than the size of the uncompressed source image. The reason for this is that the JPEG format uses 16-bit coefficients, and it is thus possible for a very high-quality JPEG image with very high-frequency content to expand rather than compress when converted to the JPEG format. Such images represent a very rare corner case, but since there is no way to predict the size of a JPEG image prior to compression, the corner case has to be handled.</p>
+<p>Compress a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into a 12-bit-per-sample JPEG image. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">width</td><td>width (in pixels) of the image</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the image</td></tr>
-    <tr><td class="paramname">jpegSubsamp</td><td>the level of chrominance subsampling to be used when generating the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK source image to be compressed. This buffer should normally be <code>pitch * height</code> samples in size. However, you can also use this parameter to compress from a specific region of a larger buffer.</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the source image. Normally this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the image is unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>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:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a>. This should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.)</li>
+</ol>
+If you choose option 1, then <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to a size_t variable that holds the size of the JPEG buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>the maximum size of the buffer (in bytes) required to hold the image, or -1 if the arguments are out of bounds. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga2be2b9969d4df9ecce9b05deed273194"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga2be2b9969d4df9ecce9b05deed273194">&#9670;&nbsp;</a></span>tjBufSizeYUV2()</h2>
+<a id="ga77901b71d0471784f318ada31ff4e7bd"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga77901b71d0471784f318ada31ff4e7bd">&#9670;&nbsp;</a></span>tj3Compress16()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT unsigned long tjBufSizeYUV2 </td>
+          <td class="memname">DLLEXPORT int tj3Compress16 </td>
           <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const unsigned short *&#160;</td>
+          <td class="paramname"><em>srcBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
           <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>width</em>, </td>
         </tr>
@@ -1052,7 +1290,7 @@ YUV Image Format Notes</h2>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pad</em>, </td>
+          <td class="paramname"><em>pitch</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -1064,7 +1302,19 @@ YUV Image Format Notes</h2>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1074,28 +1324,37 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters. </p>
+<p>Compress a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into a 16-bit-per-sample lossless JPEG image. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">width</td><td>width (in pixels) of the image</td></tr>
-    <tr><td class="paramname">pad</td><td>the width of each line in each plane of the image is padded to the nearest multiple of this number of bytes (must be a power of 2.)</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the image</td></tr>
-    <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK source image to be compressed. This buffer should normally be <code>pitch * height</code> samples in size. However, you can also use this parameter to compress from a specific region of a larger buffer.</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the source image. Normally this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the image is unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>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:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a>. This should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.)</li>
+</ol>
+If you choose option 1, then <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to a size_t variable that holds the size of the JPEG buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>the size of the buffer (in bytes) required to hold the image, or -1 if the arguments are out of bounds. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gafbdce0112fd78fd38efae841443a9bcf"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gafbdce0112fd78fd38efae841443a9bcf">&#9670;&nbsp;</a></span>tjCompress2()</h2>
+<a id="ga2cc418a2dab709ad7f30f5b25905f138"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga2cc418a2dab709ad7f30f5b25905f138">&#9670;&nbsp;</a></span>tj3Compress8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjCompress2 </td>
+          <td class="memname">DLLEXPORT int tj3Compress8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1139,26 +1398,8 @@ YUV Image Format Notes</h2>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long *&#160;</td>
-          <td class="paramname"><em>jpegSize</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>jpegSubsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>jpegQual</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1168,40 +1409,37 @@ YUV Image Format Notes</h2>
       </table>
 </div><div class="memdoc">
 
-<p>Compress an RGB, grayscale, or CMYK image into a JPEG image. </p>
+<p>Compress an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into an 8-bit-per-sample JPEG image. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing RGB, grayscale, or CMYK pixels to be compressed</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK source image to be compressed. This buffer should normally be <code>pitch * height</code> samples in size. However, you can also use this parameter to compress from a specific region of a larger buffer.</td></tr>
     <tr><td class="paramname">width</td><td>width (in pixels) of the source image</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the source image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use this parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the source image. Normally this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the image is unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
     <tr><td class="paramname">height</td><td>height (in pixels) of the source image</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
-<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+    <tr><td class="paramname">jpegBuf</td><td>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:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
 <li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
-<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a>. This should ensure that the buffer never has to be re-allocated (setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> guarantees that it won't be.)</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a>. This should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.)</li>
 </ol>
-If you choose option 1, <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>pointer to an unsigned long variable that holds the size of the JPEG image buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG image buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
-    <tr><td class="paramname">jpegSubsamp</td><td>the level of chrominance subsampling to be used when generating the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
-    <tr><td class="paramname">jpegQual</td><td>the image quality of the generated JPEG image (1 = worst, 100 = best)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+If you choose option 1, then <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to a size_t variable that holds the size of the JPEG buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga7622a459b79aa1007e005b58783f875b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga7622a459b79aa1007e005b58783f875b">&#9670;&nbsp;</a></span>tjCompressFromYUV()</h2>
+<a id="ga041c870d9c669eb3f385c78f4346c43f"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga041c870d9c669eb3f385c78f4346c43f">&#9670;&nbsp;</a></span>tj3CompressFromYUV8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjCompressFromYUV </td>
+          <td class="memname">DLLEXPORT int tj3CompressFromYUV8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1222,7 +1460,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pad</em>, </td>
+          <td class="paramname"><em>align</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -1233,32 +1471,14 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
           <td class="paramtype">unsigned char **&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long *&#160;</td>
-          <td class="paramname"><em>jpegSize</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>jpegQual</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1268,39 +1488,36 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Compress a YUV planar image into a JPEG image. </p>
+<p>Compress an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample JPEG image. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing a YUV planar image to be compressed. The size of this buffer should match the value returned by <a class="el" href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.">tjBufSizeYUV2()</a> for the given image width, height, padding, and level of chrominance subsampling. The Y, U (Cb), and V (Cr) image planes should be stored sequentially in the source buffer (refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
-    <tr><td class="paramname">width</td><td>width (in pixels) of the source image. If the width is not an even multiple of the MCU block width (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">pad</td><td>the line padding used in the source image. For instance, if each line in each plane of the YUV image is padded to the nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the source image. If the height is not an even multiple of the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling used in the source image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
-<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546" title="The size of the buffer (in bytes) required to hold a unified planar YUV image with the given paramete...">tj3YUVBufSize()</a> for the given image width, height, row alignment, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) The Y, U (Cb), and V (Cr) image planes should be stored sequentially in the buffer. (Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image. If the width is not an even multiple of the MCU block width (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed.</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image. If the height is not an even multiple of the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed.</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>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:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
 <li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
-<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a>. This should ensure that the buffer never has to be re-allocated (setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> guarantees that it won't be.)</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a>. This should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.)</li>
 </ol>
-If you choose option 1, <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>pointer to an unsigned long variable that holds the size of the JPEG image buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG image buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
-    <tr><td class="paramname">jpegQual</td><td>the image quality of the generated JPEG image (1 = worst, 100 = best)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+If you choose option 1, then <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to a size_t variable that holds the size of the JPEG buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga29ec5dfbd2d84b8724e951d6fa0d5d9e"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga29ec5dfbd2d84b8724e951d6fa0d5d9e">&#9670;&nbsp;</a></span>tjCompressFromYUVPlanes()</h2>
+<a id="gac9f5ace3e73805b476c95dda9f8d0cd0"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gac9f5ace3e73805b476c95dda9f8d0cd0">&#9670;&nbsp;</a></span>tj3CompressFromYUVPlanes8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjCompressFromYUVPlanes </td>
+          <td class="memname">DLLEXPORT int tj3CompressFromYUVPlanes8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1308,7 +1525,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">const unsigned char **&#160;</td>
+          <td class="paramtype">const unsigned char *const *&#160;</td>
           <td class="paramname"><em>srcPlanes</em>, </td>
         </tr>
         <tr>
@@ -1332,32 +1549,14 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
           <td class="paramtype">unsigned char **&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long *&#160;</td>
-          <td class="paramname"><em>jpegSize</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>jpegQual</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1367,39 +1566,36 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Compress a set of Y, U (Cb), and V (Cr) image planes into a JPEG image. </p>
+<p>Compress a set of 8-bit-per-sample Y, U (Cb), and V (Cr) image planes into an 8-bit-per-sample JPEG image. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcPlanes</td><td>an array of pointers to Y, U (Cb), and V (Cr) image planes (or just a Y plane, if compressing a grayscale image) that contain a YUV image to be compressed. These planes can be contiguous or non-contiguous in memory. The size of each plane should match the value returned by <a class="el" href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tjPlaneSizeYUV()</a> for the given image width, height, strides, and level of chrominance subsampling. Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
-    <tr><td class="paramname">width</td><td>width (in pixels) of the source image. If the width is not an even multiple of the MCU block width (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">strides</td><td>an array of integers, each specifying the number of bytes per line 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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> is NULL, then the strides for all planes will be set to their respective plane widths. You can adjust the strides in order to specify an arbitrary amount of line padding in each plane or to create a JPEG image from a subregion of a larger YUV planar image.</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the source image. If the height is not an even multiple of the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling used in the source image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
-<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tj3YUVPlaneSize()</a> for the given image width, height, strides, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the source image. If the width is not an even multiple of the MCU block width (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed.</td></tr>
+    <tr><td class="paramname">strides</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> 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.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the source image. If the height is not an even multiple of the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed.</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>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:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
 <li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
-<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a>. This should ensure that the buffer never has to be re-allocated (setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> guarantees that it won't be.)</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a>. This should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.)</li>
 </ol>
-If you choose option 1, <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>pointer to an unsigned long variable that holds the size of the JPEG image buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG image buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
-    <tr><td class="paramname">jpegQual</td><td>the image quality of the generated JPEG image (1 = worst, 100 = best)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+If you choose option 1, then <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>pointer to a size_t variable that holds the size of the JPEG buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) If <code>*jpegBuf</code> points to a JPEG buffer that is being reused from a previous call to one of the JPEG compression functions, then <code>*jpegSize</code> is ignored.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga70abbf38f77a26fd6da8813bef96f695"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga70abbf38f77a26fd6da8813bef96f695">&#9670;&nbsp;</a></span>tjDecodeYUV()</h2>
+<a id="gaa1eb574f38b1c1de43a6c7aafcf68d8c"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa1eb574f38b1c1de43a6c7aafcf68d8c">&#9670;&nbsp;</a></span>tj3DecodeYUV8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecodeYUV </td>
+          <td class="memname">DLLEXPORT int tj3DecodeYUV8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1414,13 +1610,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pad</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
+          <td class="paramname"><em>align</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -1450,13 +1640,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pixelFormat</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1466,35 +1650,33 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Decode a YUV planar image into an RGB or grayscale image. </p>
-<p>This function uses the accelerated color conversion routines in the underlying codec but does not execute any of the other steps in the JPEG decompression process.</p>
+<p>Decode an 8-bit-per-sample unified planar YUV image into an 8-bit-per-sample packed-pixel RGB or grayscale image. </p>
+<p>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.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing a YUV planar image to be decoded. The size of this buffer should match the value returned by <a class="el" href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.">tjBufSizeYUV2()</a> for the given image width, height, padding, and level of chrominance subsampling. The Y, U (Cb), and V (Cr) image planes should be stored sequentially in the source buffer (refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
-    <tr><td class="paramname">pad</td><td>Use this parameter to specify that the width of each line in each plane of the YUV source image is padded to the nearest multiple of this number of bytes (must be a power of 2.)</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling used in the YUV source image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
-    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer that will receive the decoded image. This buffer should normally be <code>pitch * height</code> bytes in size, but the <code>dstBuf</code> pointer can also be used to decode into a specific region of a larger buffer.</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546" title="The size of the buffer (in bytes) required to hold a unified planar YUV image with the given paramete...">tj3YUVBufSize()</a> for the given image width, height, row alignment, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) The Y, U (Cb), and V (Cr) image planes should be stored sequentially in the source buffer. (Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the packed-pixel decoded image. This buffer should normally be <code>pitch * height</code> bytes in size. However, you can also use this parameter to decode into a specific region of a larger buffer.</td></tr>
     <tr><td class="paramname">width</td><td>width (in pixels) of the source and destination images</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the destination image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the destination image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the destination image should be padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use the pitch parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per row in the destination image. Normally this should be set to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the destination image should be unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
     <tr><td class="paramname">height</td><td>height (in pixels) of the source and destination images</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga10e837c07fa9d25770565b237d3898d9"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga10e837c07fa9d25770565b237d3898d9">&#9670;&nbsp;</a></span>tjDecodeYUVPlanes()</h2>
+<a id="gad366f1915f82c1ad4e7e37ebe073ca89"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gad366f1915f82c1ad4e7e37ebe073ca89">&#9670;&nbsp;</a></span>tj3DecodeYUVPlanes8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecodeYUVPlanes </td>
+          <td class="memname">DLLEXPORT int tj3DecodeYUVPlanes8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1502,7 +1684,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">const unsigned char **&#160;</td>
+          <td class="paramtype">const unsigned char *const *&#160;</td>
           <td class="paramname"><em>srcPlanes</em>, </td>
         </tr>
         <tr>
@@ -1514,12 +1696,6 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
           <td class="paramtype">unsigned char *&#160;</td>
           <td class="paramname"><em>dstBuf</em>, </td>
         </tr>
@@ -1545,13 +1721,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pixelFormat</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1561,35 +1731,33 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Decode a set of Y, U (Cb), and V (Cr) image planes into an RGB or grayscale image. </p>
-<p>This function uses the accelerated color conversion routines in the underlying codec but does not execute any of the other steps in the JPEG decompression process.</p>
+<p>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. </p>
+<p>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.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tjPlaneSizeYUV()</a> for the given image width, height, strides, and level of chrominance subsampling. Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
-    <tr><td class="paramname">strides</td><td>an array of integers, each specifying the number of bytes per line 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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> is NULL, then the strides for all planes will be set to their respective plane widths. You can adjust the strides in order to specify an arbitrary amount of line padding in each plane or to decode a subregion of a larger YUV planar image.</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling used in the YUV source image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
-    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer that will receive the decoded image. This buffer should normally be <code>pitch * height</code> bytes in size, but the <code>dstBuf</code> pointer can also be used to decode into a specific region of a larger buffer.</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">srcPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tj3YUVPlaneSize()</a> for the given image width, height, strides, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
+    <tr><td class="paramname">strides</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> 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.</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the packed-pixel decoded image. This buffer should normally be <code>pitch * height</code> bytes in size. However, you can also use this parameter to decode into a specific region of a larger buffer.</td></tr>
     <tr><td class="paramname">width</td><td>width (in pixels) of the source and destination images</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the destination image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the destination image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the destination image should be padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use the pitch parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per row in the destination image. Normally this should be set to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the destination image should be unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
     <tr><td class="paramname">height</td><td>height (in pixels) of the source and destination images</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gae9eccef8b682a48f43a9117c231ed013"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gae9eccef8b682a48f43a9117c231ed013">&#9670;&nbsp;</a></span>tjDecompress2()</h2>
+<a id="ga39b848f01781ad74a5b3941c012b6199"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga39b848f01781ad74a5b3941c012b6199">&#9670;&nbsp;</a></span>tj3Decompress12()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecompress2 </td>
+          <td class="memname">DLLEXPORT int tj3Decompress12 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1603,44 +1771,26 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">short *&#160;</td>
           <td class="paramname"><em>dstBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>pitch</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pixelFormat</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1650,33 +1800,31 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Decompress a JPEG image to an RGB, grayscale, or CMYK image. </p>
+<p>Decompress a 12-bit-per-sample JPEG image into a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image. </p>
+<p>The <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when this function returns.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to decompress</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG image to decompress</td></tr>
     <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
-    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer that will receive the decompressed image. This buffer should normally be <code>pitch * scaledHeight</code> bytes in size, where <code>scaledHeight</code> can be determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a> with the JPEG image height and one of the scaling factors returned by <a class="el" href="group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057" title="Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of Tur...">tjGetScalingFactors()</a>. The <code>dstBuf</code> pointer may also be used to decompress into a specific region of a larger buffer.</td></tr>
-    <tr><td class="paramname">width</td><td>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 <code>width</code> is set to 0, then only the height will be considered when determining the scaled image size.</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the destination image. Normally, this is <code>scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the decompressed image is unpadded, else <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the decompressed image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. (NOTE: <code>scaledWidth</code> can be determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a> with the JPEG image width and one of the scaling factors returned by <a class="el" href="group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057" title="Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of Tur...">tjGetScalingFactors()</a>.) You can also be clever and use the pitch parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>scaledWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
-    <tr><td class="paramname">height</td><td>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 <code>height</code> is set to 0, then only the width will be considered when determining the scaled image size.</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the packed-pixel decompressed image. This buffer should normally be <code>pitch * destinationHeight</code> 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 <code>destinationHeight</code> is either the scaled JPEG height (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the height of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationHeight</code> is the JPEG height.</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the destination image. Normally this should be set to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the destination image should be unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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 <code>destinationWidth</code> is either the scaled JPEG width (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the width of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationWidth</code> is the JPEG width.</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga0595681096bba7199cc6f3533cb25f77"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga0595681096bba7199cc6f3533cb25f77">&#9670;&nbsp;</a></span>tjDecompressHeader3()</h2>
+<a id="gaa074e63f9beb0b3ff42b833a4049df6e"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa074e63f9beb0b3ff42b833a4049df6e">&#9670;&nbsp;</a></span>tj3Decompress16()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecompressHeader3 </td>
+          <td class="memname">DLLEXPORT int tj3Decompress16 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1690,32 +1838,26 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
+          <td class="paramtype">unsigned short *&#160;</td>
+          <td class="paramname"><em>dstBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>jpegSubsamp</em>, </td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>jpegColorspace</em>&#160;</td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1725,31 +1867,31 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Retrieve information about a JPEG image without decompressing it, or prime the decompressor with quantization and Huffman tables. </p>
+<p>Decompress a 16-bit-per-sample lossless JPEG image into a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image. </p>
+<p>The <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when this function returns.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>pointer to a 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.</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image or tables-only datastream (in bytes)</td></tr>
-    <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the JPEG image. If <code>jpegBuf</code> points to a tables-only datastream, then <code>width</code> is ignored.</td></tr>
-    <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the JPEG image. If <code>jpegBuf</code> points to a tables-only datastream, then <code>height</code> is ignored.</td></tr>
-    <tr><td class="paramname">jpegSubsamp</td><td>pointer to an integer variable that will receive the level of chrominance subsampling used when the JPEG image was compressed (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.) If <code>jpegBuf</code> points to a tables-only datastream, then <code>jpegSubsamp</code> is ignored.</td></tr>
-    <tr><td class="paramname">jpegColorspace</td><td>pointer to an integer variable that will receive one of the JPEG colorspace constants, indicating the colorspace of the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720">JPEG colorspaces</a>.) If <code>jpegBuf</code> points to a tables-only datastream, then <code>jpegColorspace</code> is ignored.</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG image to decompress</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the packed-pixel decompressed image. This buffer should normally be <code>pitch * destinationHeight</code> 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 <code>destinationHeight</code> is either the scaled JPEG height (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the height of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationHeight</code> is the JPEG height.</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the destination image. Normally this should be set to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the destination image should be unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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 <code>destinationWidth</code> is either the scaled JPEG width (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the width of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationWidth</code> is the JPEG width.</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga04d1e839ff9a0860dd1475cff78d3364"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga04d1e839ff9a0860dd1475cff78d3364">&#9670;&nbsp;</a></span>tjDecompressToYUV2()</h2>
+<a id="ga1169c7c1a26ec18c9e6122cb8ae64013"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga1169c7c1a26ec18c9e6122cb8ae64013">&#9670;&nbsp;</a></span>tj3Decompress8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecompressToYUV2 </td>
+          <td class="memname">DLLEXPORT int tj3Decompress8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1763,7 +1905,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
@@ -1776,25 +1918,62 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
+          <td class="paramname"><em>pitch</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pad</em>, </td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK image. </p>
+<p>The <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when this function returns.</p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG image to decompress</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the packed-pixel decompressed image. This buffer should normally be <code>pitch * destinationHeight</code> 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 <code>destinationHeight</code> is either the scaled JPEG height (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the height of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationHeight</code> is the JPEG height.</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the destination image. Normally this should be set to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the destination image should be unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>destinationWidth * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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 <code>destinationWidth</code> is either the scaled JPEG width (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>) or the width of the cropping region (see <a class="el" href="group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c" title="Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image.">tj3SetCroppingRegion()</a>.) If the JPEG image is lossless, then <code>destinationWidth</code> is the JPEG width.</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the destination image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="ga96d2c4b3432f9d88ad14758ae240b8d1"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga96d2c4b3432f9d88ad14758ae240b8d1">&#9670;&nbsp;</a></span>tj3DecompressHeader()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3DecompressHeader </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
+          <td class="paramtype">const unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
+          <td class="paramname"><em>jpegSize</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1804,33 +1983,28 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Decompress a JPEG image to a YUV planar image. </p>
-<p>This function performs JPEG decompression but leaves out the color conversion step, so a planar YUV image is generated instead of an RGB image.</p>
+<p>Retrieve information about a JPEG image without decompressing it, or prime the decompressor with quantization and Huffman tables. </p>
+<p>If a JPEG image is passed to this function, then the <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when the function returns.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to decompress</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
-    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer that will receive the YUV image. Use <a class="el" href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.">tjBufSizeYUV2()</a> to determine the appropriate size for this buffer based on the image width, height, padding, and level of subsampling. The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the buffer (refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
-    <tr><td class="paramname">width</td><td>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 <code>width</code> 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 <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">pad</td><td>the width of each line in each plane of the YUV image will be padded to the nearest multiple of this number of bytes (must be a power of 2.) To generate images suitable for X Video, <code>pad</code> should be set to 4.</td></tr>
-    <tr><td class="paramname">height</td><td>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 <code>height</code> 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 <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>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.</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image or tables-only datastream (in bytes)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gaa59f901a5258ada5bd0185ad59368540"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gaa59f901a5258ada5bd0185ad59368540">&#9670;&nbsp;</a></span>tjDecompressToYUVPlanes()</h2>
+<a id="ga1e6bf6a19fec3f9fa7534348879d8320"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga1e6bf6a19fec3f9fa7534348879d8320">&#9670;&nbsp;</a></span>tj3DecompressToYUV8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDecompressToYUVPlanes </td>
+          <td class="memname">DLLEXPORT int tj3DecompressToYUV8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1844,38 +2018,80 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned long&#160;</td>
+          <td class="paramtype">size_t&#160;</td>
           <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char **&#160;</td>
-          <td class="paramname"><em>dstPlanes</em>, </td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>dstBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
+          <td class="paramname"><em>align</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Decompress an 8-bit-per-sample JPEG image into an 8-bit-per-sample unified planar YUV image. </p>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when this function returns.</p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG image to decompress</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the unified planar YUV decompressed image. Use <a class="el" href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546" title="The size of the buffer (in bytes) required to hold a unified planar YUV image with the given paramete...">tj3YUVBufSize()</a> to determine the appropriate size for this buffer based on the scaled JPEG width and height (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>), row alignment, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the buffer. (Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
+    <tr><td class="paramname">align</td><td>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, <code>align</code> should be set to 4.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="ga934373482dbbf257f2280505b6ff4fb5"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga934373482dbbf257f2280505b6ff4fb5">&#9670;&nbsp;</a></span>tj3DecompressToYUVPlanes8()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3DecompressToYUVPlanes8 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>strides</em>, </td>
+          <td class="paramtype">const unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
+          <td class="paramtype">size_t&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>dstPlanes</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>strides</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -1885,33 +2101,30 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image planes. </p>
-<p>This function performs JPEG decompression but leaves out the color conversion step, so a planar YUV image is generated instead of an RGB image.</p>
+<p>Decompress an 8-bit-per-sample JPEG image into separate 8-bit-per-sample Y, U (Cb), and V (Cr) image planes. </p>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a> that describe the JPEG image will be set when this function returns.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG decompressor or transformer instance</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG image to decompress</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG image to decompress</td></tr>
     <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (in bytes)</td></tr>
-    <tr><td class="paramname">dstPlanes</td><td>an array of pointers to Y, U (Cb), and V (Cr) image planes (or just a Y plane, if decompressing a grayscale image) that will receive the YUV image. These planes can be contiguous or non-contiguous in memory. Use <a class="el" href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tjPlaneSizeYUV()</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
-    <tr><td class="paramname">width</td><td>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 <code>width</code> 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 <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">strides</td><td>an array of integers, each specifying the number of bytes per line in the corresponding plane of the output image. Setting the stride for any plane to 0 is the same as setting it to the scaled plane width (see <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> is NULL, then the strides for all planes will be set to their respective scaled plane widths. You can adjust the strides in order to add an arbitrary amount of line padding to each plane or to decompress the JPEG image into a subregion of a larger YUV planar image.</td></tr>
-    <tr><td class="paramname">height</td><td>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 <code>height</code> 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 <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>), then an intermediate buffer copy will be performed within TurboJPEG.</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+    <tr><td class="paramname">dstPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tj3YUVPlaneSize()</a> to determine the appropriate size for each plane based on the scaled JPEG width and height (see <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a>, <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>, and <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>), strides, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
+    <tr><td class="paramname">strides</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> 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.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga75f355fa27225ba1a4ee392c852394d2"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga75f355fa27225ba1a4ee392c852394d2">&#9670;&nbsp;</a></span>tjDestroy()</h2>
+<a id="ga53fbadf4560e95a65b8f5ab81703fe82"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga53fbadf4560e95a65b8f5ab81703fe82">&#9670;&nbsp;</a></span>tj3Destroy()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjDestroy </td>
+          <td class="memname">DLLEXPORT void tj3Destroy </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em></td><td>)</td>
@@ -1920,25 +2133,24 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Destroy a TurboJPEG compressor, decompressor, or transformer instance. </p>
+<p>Destroy a TurboJPEG instance. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor, decompressor or transformer instance</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance. If the handle is NULL, then this function has no effect. </td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gac519b922cdf446e97d0cdcba513636bf"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gac519b922cdf446e97d0cdcba513636bf">&#9670;&nbsp;</a></span>tjEncodeYUV3()</h2>
+<a id="ga2a8d50f130bde10f0a04030f8cc59936"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga2a8d50f130bde10f0a04030f8cc59936">&#9670;&nbsp;</a></span>tj3EncodeYUV8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjEncodeYUV3 </td>
+          <td class="memname">DLLEXPORT int tj3EncodeYUV8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -1983,19 +2195,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pad</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>align</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2005,35 +2205,33 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Encode an RGB or grayscale image into a YUV planar image. </p>
-<p>This function uses the accelerated color conversion routines in the underlying codec but does not execute any of the other steps in the JPEG compression process.</p>
+<p>Encode an 8-bit-per-sample packed-pixel RGB or grayscale image into an 8-bit-per-sample unified planar YUV image. </p>
+<p>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.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing RGB or grayscale pixels to be encoded</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to a buffer containing a packed-pixel RGB or grayscale source image to be encoded. This buffer should normally be <code>pitch * height</code> bytes in size. However, you can also use this parameter to encode from a specific region of a larger buffer.</td></tr>
     <tr><td class="paramname">width</td><td>width (in pixels) of the source image</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the source image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use this parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per row in the source image. Normally this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the image is unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
     <tr><td class="paramname">height</td><td>height (in pixels) of the source image</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">dstBuf</td><td>pointer to an image buffer that will receive the YUV image. Use <a class="el" href="group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194" title="The size of the buffer (in bytes) required to hold a YUV planar image with the given parameters.">tjBufSizeYUV2()</a> to determine the appropriate size for this buffer based on the image width, height, padding, and level of chrominance subsampling. The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the buffer (refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
-    <tr><td class="paramname">pad</td><td>the width of each line in each plane of the YUV image will be padded to the nearest multiple of this number of bytes (must be a power of 2.) To generate images suitable for X Video, <code>pad</code> should be set to 4.</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling to be used when generating the YUV image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.) To generate images suitable for X Video, <code>subsamp</code> should be set to <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737">TJSAMP_420</a>. This produces an image compatible with the I420 (AKA "YUV420P") format.</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+    <tr><td class="paramname">dstBuf</td><td>pointer to a buffer that will receive the unified planar YUV image. Use <a class="el" href="group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546" title="The size of the buffer (in bytes) required to hold a unified planar YUV image with the given paramete...">tj3YUVBufSize()</a> to determine the appropriate size for this buffer based on the image width, height, row alignment, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the buffer. (Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.)</td></tr>
+    <tr><td class="paramname">align</td><td>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, <code>align</code> should be set to 4.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gae2d04c72457fe7f4d60cf78ab1b1feb1"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gae2d04c72457fe7f4d60cf78ab1b1feb1">&#9670;&nbsp;</a></span>tjEncodeYUVPlanes()</h2>
+<a id="gae2e9df38790e9bddc249d04cb158a4cf"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gae2e9df38790e9bddc249d04cb158a4cf">&#9670;&nbsp;</a></span>tj3EncodeYUVPlanes8()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjEncodeYUVPlanes </td>
+          <td class="memname">DLLEXPORT int tj3EncodeYUVPlanes8 </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em>, </td>
@@ -2078,19 +2276,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>strides</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>strides</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2100,76 +2286,112 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Encode an RGB or grayscale image into separate Y, U (Cb), and V (Cr) image planes. </p>
-<p>This function uses the accelerated color conversion routines in the underlying codec but does not execute any of the other steps in the JPEG compression process.</p>
+<p>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. </p>
+<p>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.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance</td></tr>
-    <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing RGB or grayscale pixels to be encoded</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for compression</td></tr>
+    <tr><td class="paramname">srcBuf</td><td>pointer to a buffer containing a packed-pixel RGB or grayscale source image to be encoded. This buffer should normally be <code>pitch * height</code> bytes in size. However, you can also use this parameter to encode from a specific region of a larger buffer.</td></tr>
     <tr><td class="paramname">width</td><td>width (in pixels) of the source image</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the source image. Normally, this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code> if the image is unpadded, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511" title="Pad the given width to the nearest 32-bit boundary.">TJPAD</a>(width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat])</code> if each line of the image is padded to the nearest 32-bit boundary, as is the case for Windows bitmaps. You can also be clever and use this parameter to skip lines, etc. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">pitch</td><td>bytes per row in the source image. Normally this should be <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>, if the image is unpadded. (Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.) 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.</td></tr>
     <tr><td class="paramname">height</td><td>height (in pixels) of the source image</td></tr>
     <tr><td class="paramname">pixelFormat</td><td>pixel format of the source image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.)</td></tr>
-    <tr><td class="paramname">dstPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tjPlaneSizeYUV()</a> to determine the appropriate size for each plane based on the image width, height, strides, and level of chrominance subsampling. Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
-    <tr><td class="paramname">strides</td><td>an array of integers, each specifying the number of bytes per line in the corresponding plane of the output image. Setting the stride for any plane to 0 is the same as setting it to the plane width (see <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> is NULL, then the strides for all planes will be set to their respective plane widths. You can adjust the strides in order to add an arbitrary amount of line padding to each plane or to encode an RGB or grayscale image into a subregion of a larger YUV planar image.</td></tr>
-    <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling to be used when generating the YUV image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.) To generate images suitable for X Video, <code>subsamp</code> should be set to <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737">TJSAMP_420</a>. This produces an image compatible with the I420 (AKA "YUV420P") format.</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+    <tr><td class="paramname">dstPlanes</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d" title="The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters.">tj3YUVPlaneSize()</a> to determine the appropriate size for each plane based on the image width, height, strides, and level of chrominance subsampling (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>.) Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for more details.</td></tr>
+    <tr><td class="paramname">strides</td><td>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 <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a>.) If <code>strides</code> 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.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gaea863d2da0cdb609563aabdf9196514b"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gaea863d2da0cdb609563aabdf9196514b">&#9670;&nbsp;</a></span>tjFree()</h2>
+<a id="gaddb84fb6c81769e9faa0f5a63b296606"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaddb84fb6c81769e9faa0f5a63b296606">&#9670;&nbsp;</a></span>tj3Free()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT void tjFree </td>
+          <td class="memname">DLLEXPORT void tj3Free </td>
           <td>(</td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">void *&#160;</td>
           <td class="paramname"><em>buffer</em></td><td>)</td>
           <td></td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Free an image buffer previously allocated by TurboJPEG. </p>
-<p>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 <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a>.</p>
+<p>Free a byte buffer previously allocated by TurboJPEG. </p>
+<p>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 <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a>.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
     <tr><td class="paramname">buffer</td><td>address of the buffer to free. If the address is NULL, then this function has no effect.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> </dd></dl>
+<dl class="section see"><dt>See also</dt><dd><a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> </dd></dl>
 
 </div>
 </div>
-<a id="ga414feeffbf860ebd31c745df203de410"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga414feeffbf860ebd31c745df203de410">&#9670;&nbsp;</a></span>tjGetErrorCode()</h2>
+<a id="ga34af9ba3183bdf0ec7c8f47bb9a4c84f"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga34af9ba3183bdf0ec7c8f47bb9a4c84f">&#9670;&nbsp;</a></span>tj3Get()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjGetErrorCode </td>
+          <td class="memname">DLLEXPORT int tj3Get </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
-          <td class="paramname"><em>handle</em></td><td>)</td>
-          <td></td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
-      </table>
-</div><div class="memdoc">
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>param</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Get the value of a parameter. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">param</td><td>one of the <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a></td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>the value of the specified parameter, or -1 if the value is unknown. </dd></dl>
+
+</div>
+</div>
+<a id="gab8c8279f1415fe425ff30dbbc56013bd"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gab8c8279f1415fe425ff30dbbc56013bd">&#9670;&nbsp;</a></span>tj3GetErrorCode()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3GetErrorCode </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
 
 <p>Returns a code indicating the severity of the last error. </p>
 <p>See <a class="el" href="group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe">Error codes</a>.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor, decompressor or transformer instance</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
   </table>
   </dd>
 </dl>
@@ -2177,14 +2399,14 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
 
 </div>
 </div>
-<a id="ga1ead8574f9f39fbafc6b497124e7aafa"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga1ead8574f9f39fbafc6b497124e7aafa">&#9670;&nbsp;</a></span>tjGetErrorStr2()</h2>
+<a id="gaf2aab0e6dbb3edc57646b0fec25e8bb2"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaf2aab0e6dbb3edc57646b0fec25e8bb2">&#9670;&nbsp;</a></span>tj3GetErrorStr()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT char* tjGetErrorStr2 </td>
+          <td class="memname">DLLEXPORT char* tj3GetErrorStr </td>
           <td>(</td>
           <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
           <td class="paramname"><em>handle</em></td><td>)</td>
@@ -2193,148 +2415,652 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Returns a descriptive error message explaining why the last command failed. </p>
+<p>Returns a descriptive error message explaining why the last command failed. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>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.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>a descriptive error message explaining why the last command failed. </dd></dl>
+
+</div>
+</div>
+<a id="ga74397f8e0587d4233182c72f085aaf04"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga74397f8e0587d4233182c72f085aaf04">&#9670;&nbsp;</a></span>tj3GetScalingFactors()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>* tj3GetScalingFactors </td>
+          <td>(</td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>numScalingFactors</em></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Returns a list of fractional scaling factors that the JPEG decompressor supports. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">numScalingFactors</td><td>pointer to an integer variable that will receive the number of elements in the list</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>a pointer to a list of fractional scaling factors, or NULL if an error is encountered (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="ga69c09d39f97ec30250ad3605ace7e5df"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga69c09d39f97ec30250ad3605ace7e5df">&#9670;&nbsp;</a></span>tj3Init()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> tj3Init </td>
+          <td>(</td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>initType</em></td><td>)</td>
+          <td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Create a new TurboJPEG instance. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">initType</td><td>one of the <a class="el" href="group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086">initialization options</a></td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="gac6285e58e35a35d871d7162ec5a929c4"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gac6285e58e35a35d871d7162ec5a929c4">&#9670;&nbsp;</a></span>tj3JPEGBufSize()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT size_t tj3JPEGBufSize </td>
+          <td>(</td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>jpegSubsamp</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters. </p>
+<p>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.</p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">width</td><td>width (in pixels) of the image</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the image</td></tr>
+    <tr><td class="paramname">jpegSubsamp</td><td>the level of chrominance subsampling to be used when generating the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.) <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074ac124fa8f6cb41147e3d670dfbdfb7173" title="Unknown subsampling.">TJSAMP_UNKNOWN</a> is treated like <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3" title="4:4:4 chrominance subsampling (no chrominance subsampling).">TJSAMP_444</a>, 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 <a class="el" href="group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3" title="4:4:4 chrominance subsampling (no chrominance subsampling).">TJSAMP_444</a>.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>the maximum size of the buffer (in bytes) required to hold the image, or 0 if the arguments are out of bounds. </dd></dl>
+
+</div>
+</div>
+<a id="ga1f03c26892a26d4ce077ed6a4ac40e8f"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga1f03c26892a26d4ce077ed6a4ac40e8f">&#9670;&nbsp;</a></span>tj3LoadImage12()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT short* tj3LoadImage12 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>align</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Load a 12-bit-per-sample packed-pixel image from disk into memory. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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. If the data precision of the PBMPLUS file does not match the target data precision, then upconverting or downconverting will be performed.</td></tr>
+    <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>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 <code>*pixelFormat</code> passed to the function:<ul>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a> : The packed-pixel buffer returned by this function will use the most optimal pixel format for the file type, and <code>*pixelFormat</code> will contain the ID of that pixel format upon successful return from this function.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a> : Only PGM files and 8-bit-per-pixel BMP files with a grayscale colormap can be loaded.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a> : The RGB or grayscale pixels stored in the file will be converted using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</li>
+<li>Other <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">pixel formats</a> : The packed-pixel buffer will use the specified pixel format, and pixel format conversion will be performed if necessary.</li>
+</ul>
+</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>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 <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) This buffer should be freed using <a class="el" href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606" title="Free a byte buffer previously allocated by TurboJPEG.">tj3Free()</a>. </dd></dl>
+
+</div>
+</div>
+<a id="ga638aeba63e0ccb89d472fdbf34224cfc"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga638aeba63e0ccb89d472fdbf34224cfc">&#9670;&nbsp;</a></span>tj3LoadImage16()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT unsigned short* tj3LoadImage16 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>align</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Load a 16-bit-per-sample packed-pixel image from disk into memory. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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. If the data precision of the PBMPLUS file does not match the target data precision, then upconverting or downconverting will be performed.</td></tr>
+    <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>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 <code>*pixelFormat</code> passed to the function:<ul>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a> : The packed-pixel buffer returned by this function will use the most optimal pixel format for the file type, and <code>*pixelFormat</code> will contain the ID of that pixel format upon successful return from this function.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a> : Only PGM files and 8-bit-per-pixel BMP files with a grayscale colormap can be loaded.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a> : The RGB or grayscale pixels stored in the file will be converted using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</li>
+<li>Other <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">pixel formats</a> : The packed-pixel buffer will use the specified pixel format, and pixel format conversion will be performed if necessary.</li>
+</ul>
+</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>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 <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) This buffer should be freed using <a class="el" href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606" title="Free a byte buffer previously allocated by TurboJPEG.">tj3Free()</a>. </dd></dl>
+
+</div>
+</div>
+<a id="ga565aaae7be3f8ca9099b56655c893251"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga565aaae7be3f8ca9099b56655c893251">&#9670;&nbsp;</a></span>tj3LoadImage8()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT unsigned char* tj3LoadImage8 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>align</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int *&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Load an 8-bit-per-sample packed-pixel image from disk into memory. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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. If the data precision of the PBMPLUS file does not match the target data precision, then upconverting or downconverting will be performed.</td></tr>
+    <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>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 <code>*pixelFormat</code> passed to the function:<ul>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a> : The packed-pixel buffer returned by this function will use the most optimal pixel format for the file type, and <code>*pixelFormat</code> will contain the ID of that pixel format upon successful return from this function.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a> : Only PGM files and 8-bit-per-pixel BMP files with a grayscale colormap can be loaded.</li>
+<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a> : The RGB or grayscale pixels stored in the file will be converted using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</li>
+<li>Other <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">pixel formats</a> : The packed-pixel buffer will use the specified pixel format, and pixel format conversion will be performed if necessary.</li>
+</ul>
+</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>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 <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) This buffer should be freed using <a class="el" href="group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606" title="Free a byte buffer previously allocated by TurboJPEG.">tj3Free()</a>. </dd></dl>
+
+</div>
+</div>
+<a id="ga7c64b5106d04267a46aad85f9714ad90"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga7c64b5106d04267a46aad85f9714ad90">&#9670;&nbsp;</a></span>tj3SaveImage12()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3SaveImage12 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const short *&#160;</td>
+          <td class="paramname"><em>buffer</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Save a 12-bit-per-sample packed-pixel image from memory to disk. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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.</td></tr>
+    <tr><td class="paramname">buffer</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK image to be saved</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the packed-pixel image. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the packed-pixel image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.) If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a>, 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 <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the CMYK pixels will be converted to RGB using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="ga0fd87851f4266aca24bf4594dd0c0e71"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga0fd87851f4266aca24bf4594dd0c0e71">&#9670;&nbsp;</a></span>tj3SaveImage16()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3SaveImage16 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const unsigned short *&#160;</td>
+          <td class="paramname"><em>buffer</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Save a 16-bit-per-sample packed-pixel image from memory to disk. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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.</td></tr>
+    <tr><td class="paramname">buffer</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK image to be saved</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the packed-pixel image. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the packed-pixel image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.) If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a>, 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 <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the CMYK pixels will be converted to RGB using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
+
+</div>
+</div>
+<a id="gaa4ec838988e469cc15618e4690cc8722"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa4ec838988e469cc15618e4690cc8722">&#9670;&nbsp;</a></span>tj3SaveImage8()</h2>
+
+<div class="memitem">
+<div class="memproto">
+      <table class="memname">
+        <tr>
+          <td class="memname">DLLEXPORT int tj3SaveImage8 </td>
+          <td>(</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const char *&#160;</td>
+          <td class="paramname"><em>filename</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const unsigned char *&#160;</td>
+          <td class="paramname"><em>buffer</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pitch</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pixelFormat</em>&#160;</td>
+        </tr>
+        <tr>
+          <td></td>
+          <td>)</td>
+          <td></td><td></td>
+        </tr>
+      </table>
+</div><div class="memdoc">
+
+<p>Save an 8-bit-per-sample packed-pixel image from memory to disk. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>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.)</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">filename</td><td>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.</td></tr>
+    <tr><td class="paramname">buffer</td><td>pointer to a buffer containing a packed-pixel RGB, grayscale, or CMYK image to be saved</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pitch</td><td>samples per row in the packed-pixel image. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in samples) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the packed-pixel image</td></tr>
+    <tr><td class="paramname">pixelFormat</td><td>pixel format of the packed-pixel image (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.) If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a>, 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 <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the CMYK pixels will be converted to RGB using a quick &amp; dirty algorithm that is suitable only for testing purposes. (Proper conversion between CMYK and other formats requires a color management system.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>a descriptive error message explaining why the last command failed. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gac3854476006b10787bd128f7ede48057"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gac3854476006b10787bd128f7ede48057">&#9670;&nbsp;</a></span>tjGetScalingFactors()</h2>
+<a id="gaddf92640bfee3e8622218c713e77e7db"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaddf92640bfee3e8622218c713e77e7db">&#9670;&nbsp;</a></span>tj3Set()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>* tjGetScalingFactors </td>
+          <td class="memname">DLLEXPORT int tj3Set </td>
           <td>(</td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>numscalingfactors</em></td><td>)</td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>param</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>value</em>&#160;</td>
+        </tr>
+        <tr>
           <td></td>
+          <td>)</td>
+          <td></td><td></td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Returns a list of fractional scaling factors that the JPEG decompressor in this implementation of TurboJPEG supports. </p>
+<p>Set the value of a parameter. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">numscalingfactors</td><td>pointer to an integer variable that will receive the number of elements in the list</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance</td></tr>
+    <tr><td class="paramname">param</td><td>one of the <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameters</a></td></tr>
+    <tr><td class="paramname">value</td><td>value of the parameter (refer to <a class="el" href="group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82">parameter documentation</a>)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>a pointer to a list of fractional scaling factors, or NULL if an error is encountered (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga9d63a05fc6d813f4aae06107041a37e8"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga9d63a05fc6d813f4aae06107041a37e8">&#9670;&nbsp;</a></span>tjInitCompress()</h2>
+<a id="gaa49c7bd4c9431667a043cfc93388ba1c"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaa49c7bd4c9431667a043cfc93388ba1c">&#9670;&nbsp;</a></span>tj3SetCroppingRegion()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> tjInitCompress </td>
+          <td class="memname">DLLEXPORT int tj3SetCroppingRegion </td>
           <td>(</td>
-          <td class="paramtype">void&#160;</td>
-          <td class="paramname"></td><td>)</td>
-          <td></td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>Create a TurboJPEG compressor instance. </p>
-<dl class="section return"><dt>Returns</dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
-
-</div>
-</div>
-<a id="ga52300eac3f3d9ef4bab303bc244f62d3"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga52300eac3f3d9ef4bab303bc244f62d3">&#9670;&nbsp;</a></span>tjInitDecompress()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> tjInitDecompress </td>
-          <td>(</td>
-          <td class="paramtype">void&#160;</td>
-          <td class="paramname"></td><td>)</td>
+          <td class="paramkey"></td>
           <td></td>
+          <td class="paramtype"><a class="el" href="structtjregion.html">tjregion</a>&#160;</td>
+          <td class="paramname"><em>croppingRegion</em>&#160;</td>
         </tr>
-      </table>
-</div><div class="memdoc">
-
-<p>Create a TurboJPEG decompressor instance. </p>
-<dl class="section return"><dt>Returns</dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
-
-</div>
-</div>
-<a id="ga928beff6ac248ceadf01089fc6b41957"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga928beff6ac248ceadf01089fc6b41957">&#9670;&nbsp;</a></span>tjInitTransform()</h2>
-
-<div class="memitem">
-<div class="memproto">
-      <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> tjInitTransform </td>
-          <td>(</td>
-          <td class="paramtype">void&#160;</td>
-          <td class="paramname"></td><td>)</td>
           <td></td>
+          <td>)</td>
+          <td></td><td></td>
         </tr>
       </table>
 </div><div class="memdoc">
 
-<p>Create a new TurboJPEG transformer instance. </p>
-<dl class="section return"><dt>Returns</dt><dd>a handle to the newly-created instance, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
+<p>Set the cropping region for partially decompressing a lossy JPEG image into a packed-pixel image. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+  <table class="params">
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">croppingRegion</td><td><a class="el" href="structtjregion.html" title="Cropping region.">tjregion</a> structure that specifies a subregion of the JPEG image to decompress, or <code><a class="el" href="group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf" title="A tjregion structure that specifies no cropping.">TJUNCROPPED</a></code> for no cropping. The left boundary of the cropping region must be evenly divisible by the scaled MCU block width (<code><a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED</a>(<a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a>[subsamp], scalingFactor)</code>, where <code>subsamp</code> is the level of chrominance subsampling in the JPEG image (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a" title="Chrominance subsampling level.">TJPARAM_SUBSAMP</a>) and <code>scalingFactor</code> is the decompression scaling factor (see <a class="el" href="group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75" title="Set the scaling factor for subsequent lossy decompression operations.">tj3SetScalingFactor()</a>.) The cropping region should be specified relative to the scaled image dimensions. Unless <code>croppingRegion</code> is <code><a class="el" href="group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf" title="A tjregion structure that specifies no cropping.">TJUNCROPPED</a></code>, the JPEG header must be read (see <a class="el" href="group___turbo_j_p_e_g.html#ga96d2c4b3432f9d88ad14758ae240b8d1" title="Retrieve information about a JPEG image without decompressing it, or prime the decompressor with quan...">tj3DecompressHeader()</a>) prior to calling this function.</td></tr>
+  </table>
+  </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gaffbd83c375e79f5db4b5c5d8ad4466e7"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gaffbd83c375e79f5db4b5c5d8ad4466e7">&#9670;&nbsp;</a></span>tjLoadImage()</h2>
+<a id="ga89da17ee1e43ff423382cbc145803c75"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga89da17ee1e43ff423382cbc145803c75">&#9670;&nbsp;</a></span>tj3SetScalingFactor()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT unsigned char* tjLoadImage </td>
+          <td class="memname">DLLEXPORT int tj3SetScalingFactor </td>
           <td>(</td>
-          <td class="paramtype">const char *&#160;</td>
-          <td class="paramname"><em>filename</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>align</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int *&#160;</td>
-          <td class="paramname"><em>pixelFormat</em>, </td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramtype"><a class="el" href="structtjscalingfactor.html">tjscalingfactor</a>&#160;</td>
+          <td class="paramname"><em>scalingFactor</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2344,51 +3070,65 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Load an uncompressed image from disk into memory. </p>
+<p>Set the scaling factor for subsequent lossy decompression operations. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">filename</td><td>name of a file containing an uncompressed image in Windows BMP or PBMPLUS (PPM/PGM) format</td></tr>
-    <tr><td class="paramname">width</td><td>pointer to an integer variable that will receive the width (in pixels) of the uncompressed image</td></tr>
-    <tr><td class="paramname">align</td><td>row alignment of the image buffer to be returned (must be a power of 2.) For instance, setting this parameter to 4 will cause all rows in the image buffer to be padded to the nearest 32-bit boundary, and setting this parameter to 1 will cause all rows in the image buffer to be unpadded.</td></tr>
-    <tr><td class="paramname">height</td><td>pointer to an integer variable that will receive the height (in pixels) of the uncompressed image</td></tr>
-    <tr><td class="paramname">pixelFormat</td><td>pointer to an integer variable that specifies or will receive the pixel format of the uncompressed image buffer. The behavior of <a class="el" href="group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7" title="Load an uncompressed image from disk into memory.">tjLoadImage()</a> will vary depending on the value of <code>*pixelFormat</code> passed to the function:<ul>
-<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed">TJPF_UNKNOWN</a> : The uncompressed image buffer returned by the function will use the most optimal pixel format for the file type, and <code>*pixelFormat</code> will contain the ID of this pixel format upon successful return from the function.</li>
-<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a> : Only PGM files and 8-bit BMP files with a grayscale colormap can be loaded.</li>
-<li><a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a> : The RGB or grayscale pixels stored in the file will be converted using a quick &amp; dirty algorithm that is suitable only for testing purposes (proper conversion between CMYK and other formats requires a color management system.)</li>
-<li>Other <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">pixel formats</a> : The uncompressed image buffer will use the specified pixel format, and pixel format conversion will be performed if necessary.</li>
-</ul>
-</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">flags</a>.</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for decompression</td></tr>
+    <tr><td class="paramname">scalingFactor</td><td><a class="el" href="structtjscalingfactor.html" title="Scaling factor.">tjscalingfactor</a> structure that specifies a fractional scaling factor that the decompressor supports (see <a class="el" href="group___turbo_j_p_e_g.html#ga74397f8e0587d4233182c72f085aaf04" title="Returns a list of fractional scaling factors that the JPEG decompressor supports.">tj3GetScalingFactors()</a>), or <code><a class="el" href="group___turbo_j_p_e_g.html#ga7880644a0849161ad20933536169ee19" title="A tjscalingfactor structure that specifies a scaling factor of 1/1 (no scaling)">TJUNSCALED</a></code> 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 <a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df" title="Compute the scaled value of dimension using the given scaling factor.">TJSCALED()</a> with the JPEG width and height (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8" title="JPEG width (in pixels) [decompression only, read-only].">TJPARAM_JPEGWIDTH</a> and <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f" title="JPEG height (in pixels) [decompression only, read-only].">TJPARAM_JPEGHEIGHT</a>) 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 MCU block size (see <a class="el" href="group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c" title="MCU block width (in pixels) for a given level of chrominance subsampling.">tjMCUWidth</a> and <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) Note that decompression scaling is not available (and the specified scaling factor is ignored) when decompressing lossless JPEG images (see <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f" title="Lossless JPEG.">TJPARAM_LOSSLESS</a>), since the IDCT algorithm is not used with those images. Note also that <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a6914692ac6ec5567787d592b7563f627" title="DCT/IDCT algorithm [lossy compression and decompression].">TJPARAM_FASTDCT</a> is ignored when decompression scaling is enabled.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>a pointer to a newly-allocated buffer containing the uncompressed image, converted to the chosen pixel format and with the chosen row alignment, or NULL if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) This buffer should be freed using <a class="el" href="group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b" title="Free an image buffer previously allocated by TurboJPEG.">tjFree()</a>. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="ga1a209696c6a80748f20e134b3c64789f"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga1a209696c6a80748f20e134b3c64789f">&#9670;&nbsp;</a></span>tjPlaneHeight()</h2>
+<a id="gaff23ba1dcabed456794b844791613920"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaff23ba1dcabed456794b844791613920">&#9670;&nbsp;</a></span>tj3Transform()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjPlaneHeight </td>
+          <td class="memname">DLLEXPORT int tj3Transform </td>
           <td>(</td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>componentID</em>, </td>
+          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>height</em>, </td>
+          <td class="paramtype">const unsigned char *&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">size_t&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>subsamp</em>&#160;</td>
+          <td class="paramname"><em>n</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>dstBufs</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">size_t *&#160;</td>
+          <td class="paramname"><em>dstSizes</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">const <a class="el" href="structtjtransform.html">tjtransform</a> *&#160;</td>
+          <td class="paramname"><em>transforms</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2398,43 +3138,46 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>The plane height of a YUV image plane with the given parameters. </p>
-<p>Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for a description of plane height.</p>
+<p>Losslessly transform a JPEG image into another JPEG image. </p>
+<p>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.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">componentID</td><td>ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the YUV image</td></tr>
-    <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
+    <tr><td class="paramname">handle</td><td>handle to a TurboJPEG instance that has been initialized for lossless transformation</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a byte buffer containing the JPEG source image to transform</td></tr>
+    <tr><td class="paramname">jpegSize</td><td>size of the JPEG source image (in bytes)</td></tr>
+    <tr><td class="paramname">n</td><td>the number of transformed JPEG images to generate</td></tr>
+    <tr><td class="paramname">dstBufs</td><td>pointer to an array of n byte buffers. <code>dstBufs[i]</code> will receive a JPEG image that has been transformed using the parameters in <code>transforms[i]</code>. TurboJPEG has the ability to reallocate the JPEG destination buffer to accommodate the size of the transformed JPEG image. Thus, you can choose to:<ol type="1">
+<li>pre-allocate the JPEG destination buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d" title="Allocate a byte buffer for use with TurboJPEG.">tj3Alloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>dstBufs[i]</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tj3JPEGBufSize()</a> with the transformed or cropped width and height and the level of subsampling used in the source image. Under normal circumstances, this should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> guarantees that it won't be.) Note, however, that there are some rare cases (such as transforming images with a large amount of embedded EXIF or ICC profile data) in which the transformed JPEG image will be larger than the worst-case size, and <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a> cannot be used in those cases.</li>
+</ol>
+If you choose option 1, then <code>dstSizes[i]</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b" title="JPEG destination buffer (re)allocation [compression, lossless transformation].">TJPARAM_NOREALLOC</a>, you should always check <code>dstBufs[i]</code> upon return from this function, as it may have changed.</td></tr>
+    <tr><td class="paramname">dstSizes</td><td>pointer to an array of n size_t variables that will receive the actual sizes (in bytes) of each transformed JPEG image. If <code>dstBufs[i]</code> points to a pre-allocated buffer, then <code>dstSizes[i]</code> should be set to the size of the buffer. Upon return, <code>dstSizes[i]</code> will contain the size of the transformed JPEG image (in bytes.)</td></tr>
+    <tr><td class="paramname">transforms</td><td>pointer to an array of n <a class="el" href="structtjtransform.html" title="Lossless transform.">tjtransform</a> structures, each of which specifies the transform parameters and/or cropping region for the corresponding transformed JPEG image.</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>the plane height of a YUV image plane with the given parameters, or -1 if the arguments are out of bounds. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2" title="Returns a descriptive error message explaining why the last command failed.">tj3GetErrorStr()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd" title="Returns a code indicating the severity of the last error.">tj3GetErrorCode()</a>.) </dd></dl>
 
 </div>
 </div>
-<a id="gab4ab7b24f6e797d79abaaa670373961d"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#gab4ab7b24f6e797d79abaaa670373961d">&#9670;&nbsp;</a></span>tjPlaneSizeYUV()</h2>
+<a id="gaaebaa16973a0f550a66eca5765ed0546"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gaaebaa16973a0f550a66eca5765ed0546">&#9670;&nbsp;</a></span>tj3YUVBufSize()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT unsigned long tjPlaneSizeYUV </td>
+          <td class="memname">DLLEXPORT size_t tj3YUVBufSize </td>
           <td>(</td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>componentID</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>width</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>stride</em>, </td>
+          <td class="paramname"><em>align</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -2456,29 +3199,28 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters. </p>
+<p>The size of the buffer (in bytes) required to hold a unified planar YUV image with the given parameters. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">componentID</td><td>ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)</td></tr>
-    <tr><td class="paramname">width</td><td>width (in pixels) of the YUV image. NOTE: this is the width of the whole image, not the plane width.</td></tr>
-    <tr><td class="paramname">stride</td><td>bytes per line in the image plane. Setting this to 0 is the equivalent of setting it to the plane width.</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the YUV image. NOTE: this is the height of the whole image, not the plane height.</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the image</td></tr>
+    <tr><td class="paramname">align</td><td>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.)</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the image</td></tr>
     <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>the size of the buffer (in bytes) required to hold the YUV image plane, or -1 if the arguments are out of bounds. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>the size of the buffer (in bytes) required to hold the image, or 0 if the arguments are out of bounds. </dd></dl>
 
 </div>
 </div>
-<a id="ga63fb66bb1e36c74008c4634360becbb1"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga63fb66bb1e36c74008c4634360becbb1">&#9670;&nbsp;</a></span>tjPlaneWidth()</h2>
+<a id="ga969767ec8180cc3edd99cf507f87299b"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga969767ec8180cc3edd99cf507f87299b">&#9670;&nbsp;</a></span>tj3YUVPlaneHeight()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjPlaneWidth </td>
+          <td class="memname">DLLEXPORT int tj3YUVPlaneHeight </td>
           <td>(</td>
           <td class="paramtype">int&#160;</td>
           <td class="paramname"><em>componentID</em>, </td>
@@ -2487,7 +3229,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>width</em>, </td>
+          <td class="paramname"><em>height</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -2503,37 +3245,31 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>The plane width of a YUV image plane with the given parameters. </p>
-<p>Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for a description of plane width.</p>
+<p>The plane height of a YUV image plane with the given parameters. </p>
+<p>Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for a description of plane height.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
     <tr><td class="paramname">componentID</td><td>ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)</td></tr>
-    <tr><td class="paramname">width</td><td>width (in pixels) of the YUV image</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the YUV image</td></tr>
     <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>the plane width of a YUV image plane with the given parameters, or -1 if the arguments are out of bounds. </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>the plane height of a YUV image plane with the given parameters, or 0 if the arguments are out of bounds. </dd></dl>
 
 </div>
 </div>
-<a id="ga6f445b22d8933ae4815b3370a538d879"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga6f445b22d8933ae4815b3370a538d879">&#9670;&nbsp;</a></span>tjSaveImage()</h2>
+<a id="gacc19d265edce76b46146f59579f9438d"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gacc19d265edce76b46146f59579f9438d">&#9670;&nbsp;</a></span>tj3YUVPlaneSize()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjSaveImage </td>
+          <td class="memname">DLLEXPORT size_t tj3YUVPlaneSize </td>
           <td>(</td>
-          <td class="paramtype">const char *&#160;</td>
-          <td class="paramname"><em>filename</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
-          <td class="paramname"><em>buffer</em>, </td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>componentID</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -2545,7 +3281,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pitch</em>, </td>
+          <td class="paramname"><em>stride</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
@@ -2557,13 +3293,7 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>pixelFormat</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>subsamp</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2573,76 +3303,44 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Save an uncompressed image from memory to disk. </p>
+<p>The size of the buffer (in bytes) required to hold a YUV image plane with the given parameters. </p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">filename</td><td>name of a file to which to save the uncompressed image. The image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending on the file extension.</td></tr>
-    <tr><td class="paramname">buffer</td><td>pointer to an image buffer containing RGB, grayscale, or CMYK pixels to be saved</td></tr>
-    <tr><td class="paramname">width</td><td>width (in pixels) of the uncompressed image</td></tr>
-    <tr><td class="paramname">pitch</td><td>bytes per line in the image buffer. Setting this parameter to 0 is the equivalent of setting it to <code>width * <a class="el" href="group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c" title="Pixel size (in bytes) for a given pixel format.">tjPixelSize</a>[pixelFormat]</code>.</td></tr>
-    <tr><td class="paramname">height</td><td>height (in pixels) of the uncompressed image</td></tr>
-    <tr><td class="paramname">pixelFormat</td><td>pixel format of the image buffer (see <a class="el" href="group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a">Pixel formats</a>.) If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a">TJPF_GRAY</a>, then the image will be stored in PGM or 8-bit (indexed color) BMP format. Otherwise, the image will be stored in PPM or 24-bit BMP format. If this parameter is set to <a class="el" href="group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b">TJPF_CMYK</a>, then the CMYK pixels will be converted to RGB using a quick &amp; dirty algorithm that is suitable only for testing (proper conversion between CMYK and other formats requires a color management system.)</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">flags</a>.</td></tr>
+    <tr><td class="paramname">componentID</td><td>ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the YUV image. NOTE: this is the width of the whole image, not the plane width.</td></tr>
+    <tr><td class="paramname">stride</td><td>bytes per row in the image plane. Setting this to 0 is the equivalent of setting it to the plane width.</td></tr>
+    <tr><td class="paramname">height</td><td>height (in pixels) of the YUV image. NOTE: this is the height of the whole image, not the plane height.</td></tr>
+    <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>the size of the buffer (in bytes) required to hold the YUV image plane, or 0 if the arguments are out of bounds. </dd></dl>
 
 </div>
 </div>
-<a id="ga9cb8abf4cc91881e04a0329b2270be25"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#ga9cb8abf4cc91881e04a0329b2270be25">&#9670;&nbsp;</a></span>tjTransform()</h2>
+<a id="gac99d1933ede1d59fcada9a826e88eb2d"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#gac99d1933ede1d59fcada9a826e88eb2d">&#9670;&nbsp;</a></span>tj3YUVPlaneWidth()</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">DLLEXPORT int tjTransform </td>
+          <td class="memname">DLLEXPORT int tj3YUVPlaneWidth </td>
           <td>(</td>
-          <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a>&#160;</td>
-          <td class="paramname"><em>handle</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">const unsigned char *&#160;</td>
-          <td class="paramname"><em>jpegBuf</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">unsigned long&#160;</td>
-          <td class="paramname"><em>jpegSize</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>n</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">unsigned char **&#160;</td>
-          <td class="paramname"><em>dstBufs</em>, </td>
-        </tr>
-        <tr>
-          <td class="paramkey"></td>
-          <td></td>
-          <td class="paramtype">unsigned long *&#160;</td>
-          <td class="paramname"><em>dstSizes</em>, </td>
+          <td class="paramname"><em>componentID</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype"><a class="el" href="structtjtransform.html">tjtransform</a> *&#160;</td>
-          <td class="paramname"><em>transforms</em>, </td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
           <td class="paramtype">int&#160;</td>
-          <td class="paramname"><em>flags</em>&#160;</td>
+          <td class="paramname"><em>subsamp</em>&#160;</td>
         </tr>
         <tr>
           <td></td>
@@ -2652,27 +3350,17 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
       </table>
 </div><div class="memdoc">
 
-<p>Losslessly transform a JPEG image into another JPEG image. </p>
-<p>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.</p>
+<p>The plane width of a YUV image plane with the given parameters. </p>
+<p>Refer to <a class="el" href="group___turbo_j_p_e_g.html#YUVnotes">YUV Image Format Notes</a> for a description of plane width.</p>
 <dl class="params"><dt>Parameters</dt><dd>
   <table class="params">
-    <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG transformer instance</td></tr>
-    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing the JPEG source image to transform</td></tr>
-    <tr><td class="paramname">jpegSize</td><td>size of the JPEG source image (in bytes)</td></tr>
-    <tr><td class="paramname">n</td><td>the number of transformed JPEG images to generate</td></tr>
-    <tr><td class="paramname">dstBufs</td><td>pointer to an array of n image buffers. <code>dstBufs[i]</code> will receive a JPEG image that has been transformed using the parameters in <code>transforms[i]</code>. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
-<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
-<li>set <code>dstBufs[i]</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
-<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a> with the transformed or cropped width and height. Under normal circumstances, this should ensure that the buffer never has to be re-allocated (setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> guarantees that it won't be.) Note, however, that there are some rare cases (such as transforming images with a large amount of embedded EXIF or ICC profile data) in which the output image will be larger than the worst-case size, and <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> cannot be used in those cases.</li>
-</ol>
-If you choose option 1, <code>dstSizes[i]</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>dstBufs[i]</code> upon return from this function, as it may have changed.</td></tr>
-    <tr><td class="paramname">dstSizes</td><td>pointer to an array of n unsigned long variables that will receive the actual sizes (in bytes) of each transformed JPEG image. If <code>dstBufs[i]</code> points to a pre-allocated buffer, then <code>dstSizes[i]</code> should be set to the size of the buffer. Upon return, <code>dstSizes[i]</code> will contain the size of the JPEG image (in bytes.)</td></tr>
-    <tr><td class="paramname">transforms</td><td>pointer to an array of n <a class="el" href="structtjtransform.html" title="Lossless transform.">tjtransform</a> structures, each of which specifies the transform parameters and/or cropping region for the corresponding transformed output image.</td></tr>
-    <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0">flags</a></td></tr>
+    <tr><td class="paramname">componentID</td><td>ID number of the image plane (0 = Y, 1 = U/Cb, 2 = V/Cr)</td></tr>
+    <tr><td class="paramname">width</td><td>width (in pixels) of the YUV image</td></tr>
+    <tr><td class="paramname">subsamp</td><td>level of chrominance subsampling in the image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.)</td></tr>
   </table>
   </dd>
 </dl>
-<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410" title="Returns a code indicating the severity of the last error.">tjGetErrorCode()</a>.) </dd></dl>
+<dl class="section return"><dt>Returns</dt><dd>the plane width of a YUV image plane with the given parameters, or 0 if the arguments are out of bounds. </dd></dl>
 
 </div>
 </div>
@@ -2697,8 +3385,8 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 </table>
 </div><div class="memdoc">
 
-<p>Alpha offset (in bytes) for a given pixel format. </p>
-<p>This specifies the number of bytes that the Alpha component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRA is stored in <code>char pixel[]</code>, then the alpha component will be <code>pixel[tjAlphaOffset[TJ_BGRA]]</code>. This will be -1 if the pixel format does not have an alpha component. </p>
+<p>Alpha offset (in samples) for a given pixel format. </p>
+<p>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 <code>unsigned char pixel[]</code>, then the alpha component will be <code>pixel[tjAlphaOffset[TJPF_BGRA]]</code>. This will be -1 if the pixel format does not have an alpha component. </p>
 
 </div>
 </div>
@@ -2722,8 +3410,8 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 </table>
 </div><div class="memdoc">
 
-<p>Blue offset (in bytes) for a given pixel format. </p>
-<p>This specifies the number of bytes that the Blue component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the blue component will be <code>pixel[tjBlueOffset[TJ_BGRX]]</code>. This will be -1 if the pixel format does not have a blue component. </p>
+<p>Blue offset (in samples) for a given pixel format. </p>
+<p>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 <code>unsigned char pixel[]</code>, then the blue component will be <code>pixel[tjBlueOffset[TJPF_BGRX]]</code>. This will be -1 if the pixel format does not have a blue component. </p>
 
 </div>
 </div>
@@ -2747,8 +3435,8 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 </table>
 </div><div class="memdoc">
 
-<p>Green offset (in bytes) for a given pixel format. </p>
-<p>This specifies the number of bytes that the green component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the green component will be <code>pixel[tjGreenOffset[TJ_BGRX]]</code>. This will be -1 if the pixel format does not have a green component. </p>
+<p>Green offset (in samples) for a given pixel format. </p>
+<p>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 <code>unsigned char pixel[]</code>, then the green component will be <code>pixel[tjGreenOffset[TJPF_BGRX]]</code>. This will be -1 if the pixel format does not have a green component. </p>
 
 </div>
 </div>
@@ -2778,7 +3466,8 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 <li>16x8 for 4:2:2</li>
 <li>8x16 for 4:4:0</li>
 <li>16x16 for 4:2:0</li>
-<li>32x8 for 4:1:1 </li>
+<li>32x8 for 4:1:1</li>
+<li>8x32 for 4:4:1 </li>
 </ul>
 
 </div>
@@ -2809,7 +3498,8 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 <li>16x8 for 4:2:2</li>
 <li>8x16 for 4:4:0</li>
 <li>16x16 for 4:2:0</li>
-<li>32x8 for 4:1:1 </li>
+<li>32x8 for 4:1:1</li>
+<li>8x32 for 4:4:1 </li>
 </ul>
 
 </div>
@@ -2834,7 +3524,7 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 </table>
 </div><div class="memdoc">
 
-<p>Pixel size (in bytes) for a given pixel format. </p>
+<p>Pixel size (in samples) for a given pixel format. </p>
 
 </div>
 </div>
@@ -2858,8 +3548,56 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
 </table>
 </div><div class="memdoc">
 
-<p>Red offset (in bytes) for a given pixel format. </p>
-<p>This specifies the number of bytes that the red component is offset from the start of the pixel. For instance, if a pixel of format TJ_BGRX is stored in <code>char pixel[]</code>, then the red component will be <code>pixel[tjRedOffset[TJ_BGRX]]</code>. This will be -1 if the pixel format does not have a red component. </p>
+<p>Red offset (in samples) for a given pixel format. </p>
+<p>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 <code>unsigned char pixel[]</code>, then the red component will be <code>pixel[tjRedOffset[TJPF_BGRX]]</code>. This will be -1 if the pixel format does not have a red component. </p>
+
+</div>
+</div>
+<a id="ga6f192ad58a5a5802e145149d83c643bf"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga6f192ad58a5a5802e145149d83c643bf">&#9670;&nbsp;</a></span>TJUNCROPPED</h2>
+
+<div class="memitem">
+<div class="memproto">
+<table class="mlabels">
+  <tr>
+  <td class="mlabels-left">
+      <table class="memname">
+        <tr>
+          <td class="memname">const <a class="el" href="structtjregion.html">tjregion</a> TJUNCROPPED</td>
+        </tr>
+      </table>
+  </td>
+  <td class="mlabels-right">
+<span class="mlabels"><span class="mlabel">static</span></span>  </td>
+  </tr>
+</table>
+</div><div class="memdoc">
+
+<p>A <a class="el" href="structtjregion.html" title="Cropping region.">tjregion</a> structure that specifies no cropping. </p>
+
+</div>
+</div>
+<a id="ga7880644a0849161ad20933536169ee19"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#ga7880644a0849161ad20933536169ee19">&#9670;&nbsp;</a></span>TJUNSCALED</h2>
+
+<div class="memitem">
+<div class="memproto">
+<table class="mlabels">
+  <tr>
+  <td class="mlabels-left">
+      <table class="memname">
+        <tr>
+          <td class="memname">const <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> TJUNSCALED</td>
+        </tr>
+      </table>
+  </td>
+  <td class="mlabels-right">
+<span class="mlabels"><span class="mlabel">static</span></span>  </td>
+  </tr>
+</table>
+</div><div class="memdoc">
+
+<p>A <a class="el" href="structtjscalingfactor.html" title="Scaling factor.">tjscalingfactor</a> structure that specifies a scaling factor of 1/1 (no scaling) </p>
 
 </div>
 </div>
index a6f272a..7c9ccd2 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
index d48980a..b6c30d8 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
index 54c7356..07cc58c 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['customfilter_0',['customFilter',['../structtjtransform.html#afd7fc262df33f741e120ef4183202ef5',1,'tjtransform']]]
+  ['customfilter_0',['customFilter',['../structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2',1,'tjtransform']]]
 ];
index aa31107..a3fa784 100644 (file)
 var searchData=
 [
-  ['tj_5fnumcs_8',['TJ_NUMCS',['../group___turbo_j_p_e_g.html#ga39f57a6fb02d9cf32e7b6890099b5a71',1,'turbojpeg.h']]],
-  ['tj_5fnumerr_9',['TJ_NUMERR',['../group___turbo_j_p_e_g.html#ga79bde1b4a3e2351e00887e47781b966e',1,'turbojpeg.h']]],
-  ['tj_5fnumpf_10',['TJ_NUMPF',['../group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e',1,'turbojpeg.h']]],
-  ['tj_5fnumsamp_11',['TJ_NUMSAMP',['../group___turbo_j_p_e_g.html#ga5ef3d169162ce77ce348e292a0b7477c',1,'turbojpeg.h']]],
-  ['tj_5fnumxop_12',['TJ_NUMXOP',['../group___turbo_j_p_e_g.html#ga0f6dbd18adf38b7d46ac547f0f4d562c',1,'turbojpeg.h']]],
-  ['tjalloc_13',['tjAlloc',['../group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83',1,'turbojpeg.h']]],
-  ['tjalphaoffset_14',['tjAlphaOffset',['../group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837',1,'turbojpeg.h']]],
-  ['tjblueoffset_15',['tjBlueOffset',['../group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea',1,'turbojpeg.h']]],
-  ['tjbufsize_16',['tjBufSize',['../group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90',1,'turbojpeg.h']]],
-  ['tjbufsizeyuv2_17',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194',1,'turbojpeg.h']]],
-  ['tjcompress2_18',['tjCompress2',['../group___turbo_j_p_e_g.html#gafbdce0112fd78fd38efae841443a9bcf',1,'turbojpeg.h']]],
-  ['tjcompressfromyuv_19',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga7622a459b79aa1007e005b58783f875b',1,'turbojpeg.h']]],
-  ['tjcompressfromyuvplanes_20',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#ga29ec5dfbd2d84b8724e951d6fa0d5d9e',1,'turbojpeg.h']]],
-  ['tjcs_21',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
-  ['tjcs_5fcmyk_22',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
-  ['tjcs_5fgray_23',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
-  ['tjcs_5frgb_24',['TJCS_RGB',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555',1,'turbojpeg.h']]],
-  ['tjcs_5fycbcr_25',['TJCS_YCbCr',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75',1,'turbojpeg.h']]],
-  ['tjcs_5fycck_26',['TJCS_YCCK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e',1,'turbojpeg.h']]],
-  ['tjdecodeyuv_27',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga70abbf38f77a26fd6da8813bef96f695',1,'turbojpeg.h']]],
-  ['tjdecodeyuvplanes_28',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga10e837c07fa9d25770565b237d3898d9',1,'turbojpeg.h']]],
-  ['tjdecompress2_29',['tjDecompress2',['../group___turbo_j_p_e_g.html#gae9eccef8b682a48f43a9117c231ed013',1,'turbojpeg.h']]],
-  ['tjdecompressheader3_30',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#ga0595681096bba7199cc6f3533cb25f77',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuv2_31',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga04d1e839ff9a0860dd1475cff78d3364',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuvplanes_32',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#gaa59f901a5258ada5bd0185ad59368540',1,'turbojpeg.h']]],
-  ['tjdestroy_33',['tjDestroy',['../group___turbo_j_p_e_g.html#ga75f355fa27225ba1a4ee392c852394d2',1,'turbojpeg.h']]],
-  ['tjencodeyuv3_34',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#gac519b922cdf446e97d0cdcba513636bf',1,'turbojpeg.h']]],
-  ['tjencodeyuvplanes_35',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#gae2d04c72457fe7f4d60cf78ab1b1feb1',1,'turbojpeg.h']]],
-  ['tjerr_36',['TJERR',['../group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe',1,'turbojpeg.h']]],
-  ['tjerr_5ffatal_37',['TJERR_FATAL',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a',1,'turbojpeg.h']]],
-  ['tjerr_5fwarning_38',['TJERR_WARNING',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59',1,'turbojpeg.h']]],
-  ['tjflag_5faccuratedct_39',['TJFLAG_ACCURATEDCT',['../group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0',1,'turbojpeg.h']]],
-  ['tjflag_5fbottomup_40',['TJFLAG_BOTTOMUP',['../group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec',1,'turbojpeg.h']]],
-  ['tjflag_5ffastdct_41',['TJFLAG_FASTDCT',['../group___turbo_j_p_e_g.html#gaabce235db80d3f698b27f36cbd453da2',1,'turbojpeg.h']]],
-  ['tjflag_5ffastupsample_42',['TJFLAG_FASTUPSAMPLE',['../group___turbo_j_p_e_g.html#ga4ee4506c81177a06f77e2504a22efd2d',1,'turbojpeg.h']]],
-  ['tjflag_5flimitscans_43',['TJFLAG_LIMITSCANS',['../group___turbo_j_p_e_g.html#ga163e6482dc5096831feef9c79ff3f805',1,'turbojpeg.h']]],
-  ['tjflag_5fnorealloc_44',['TJFLAG_NOREALLOC',['../group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963',1,'turbojpeg.h']]],
-  ['tjflag_5fprogressive_45',['TJFLAG_PROGRESSIVE',['../group___turbo_j_p_e_g.html#ga43b426750b46190a25d34a67ef76df1b',1,'turbojpeg.h']]],
-  ['tjflag_5fstoponwarning_46',['TJFLAG_STOPONWARNING',['../group___turbo_j_p_e_g.html#ga519cfa4ef6c18d9e5b455fdf59306a3a',1,'turbojpeg.h']]],
-  ['tjfree_47',['tjFree',['../group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b',1,'turbojpeg.h']]],
-  ['tjgeterrorcode_48',['tjGetErrorCode',['../group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410',1,'turbojpeg.h']]],
-  ['tjgeterrorstr2_49',['tjGetErrorStr2',['../group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa',1,'turbojpeg.h']]],
-  ['tjgetscalingfactors_50',['tjGetScalingFactors',['../group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057',1,'turbojpeg.h']]],
-  ['tjgreenoffset_51',['tjGreenOffset',['../group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f',1,'turbojpeg.h']]],
-  ['tjhandle_52',['tjhandle',['../group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763',1,'turbojpeg.h']]],
-  ['tjinitcompress_53',['tjInitCompress',['../group___turbo_j_p_e_g.html#ga9d63a05fc6d813f4aae06107041a37e8',1,'turbojpeg.h']]],
-  ['tjinitdecompress_54',['tjInitDecompress',['../group___turbo_j_p_e_g.html#ga52300eac3f3d9ef4bab303bc244f62d3',1,'turbojpeg.h']]],
-  ['tjinittransform_55',['tjInitTransform',['../group___turbo_j_p_e_g.html#ga928beff6ac248ceadf01089fc6b41957',1,'turbojpeg.h']]],
-  ['tjloadimage_56',['tjLoadImage',['../group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7',1,'turbojpeg.h']]],
-  ['tjmcuheight_57',['tjMCUHeight',['../group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf',1,'turbojpeg.h']]],
-  ['tjmcuwidth_58',['tjMCUWidth',['../group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c',1,'turbojpeg.h']]],
-  ['tjpad_59',['TJPAD',['../group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511',1,'turbojpeg.h']]],
-  ['tjpf_60',['TJPF',['../group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a',1,'turbojpeg.h']]],
-  ['tjpf_5fabgr_61',['TJPF_ABGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081',1,'turbojpeg.h']]],
-  ['tjpf_5fargb_62',['TJPF_ARGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c',1,'turbojpeg.h']]],
-  ['tjpf_5fbgr_63',['TJPF_BGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aab10624437fb8ef495a0b153e65749839',1,'turbojpeg.h']]],
-  ['tjpf_5fbgra_64',['TJPF_BGRA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4',1,'turbojpeg.h']]],
-  ['tjpf_5fbgrx_65',['TJPF_BGRX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8',1,'turbojpeg.h']]],
-  ['tjpf_5fcmyk_66',['TJPF_CMYK',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b',1,'turbojpeg.h']]],
-  ['tjpf_5fgray_67',['TJPF_GRAY',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a',1,'turbojpeg.h']]],
-  ['tjpf_5frgb_68',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
-  ['tjpf_5frgba_69',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
-  ['tjpf_5frgbx_70',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
-  ['tjpf_5funknown_71',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
-  ['tjpf_5fxbgr_72',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
-  ['tjpf_5fxrgb_73',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
-  ['tjpixelsize_74',['tjPixelSize',['../group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c',1,'turbojpeg.h']]],
-  ['tjplaneheight_75',['tjPlaneHeight',['../group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f',1,'turbojpeg.h']]],
-  ['tjplanesizeyuv_76',['tjPlaneSizeYUV',['../group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d',1,'turbojpeg.h']]],
-  ['tjplanewidth_77',['tjPlaneWidth',['../group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1',1,'turbojpeg.h']]],
-  ['tjredoffset_78',['tjRedOffset',['../group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8',1,'turbojpeg.h']]],
-  ['tjregion_79',['tjregion',['../structtjregion.html',1,'']]],
-  ['tjsamp_80',['TJSAMP',['../group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074',1,'turbojpeg.h']]],
-  ['tjsamp_5f411_81',['TJSAMP_411',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2',1,'turbojpeg.h']]],
-  ['tjsamp_5f420_82',['TJSAMP_420',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737',1,'turbojpeg.h']]],
-  ['tjsamp_5f422_83',['TJSAMP_422',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a136130902cc578f11f32429b59368404',1,'turbojpeg.h']]],
-  ['tjsamp_5f440_84',['TJSAMP_440',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974',1,'turbojpeg.h']]],
-  ['tjsamp_5f444_85',['TJSAMP_444',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3',1,'turbojpeg.h']]],
-  ['tjsamp_5fgray_86',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
-  ['tjsaveimage_87',['tjSaveImage',['../group___turbo_j_p_e_g.html#ga6f445b22d8933ae4815b3370a538d879',1,'turbojpeg.h']]],
-  ['tjscaled_88',['TJSCALED',['../group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df',1,'turbojpeg.h']]],
-  ['tjscalingfactor_89',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
-  ['tjtransform_90',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#ga504805ec0161f1b505397ca0118bf8fd',1,'tjtransform():&#160;turbojpeg.h'],['../group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25',1,'tjTransform(tjhandle handle, const unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags):&#160;turbojpeg.h']]],
-  ['tjxop_91',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]],
-  ['tjxop_5fhflip_92',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
-  ['tjxop_5fnone_93',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
-  ['tjxop_5frot180_94',['TJXOP_ROT180',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a140952eb8dd0300accfcc22726d69692',1,'turbojpeg.h']]],
-  ['tjxop_5frot270_95',['TJXOP_ROT270',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08',1,'turbojpeg.h']]],
-  ['tjxop_5frot90_96',['TJXOP_ROT90',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a43b2bbb23bc4bd548422d43fbe9af128',1,'turbojpeg.h']]],
-  ['tjxop_5ftranspose_97',['TJXOP_TRANSPOSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a31060aed199f886afdd417f80499c32d',1,'turbojpeg.h']]],
-  ['tjxop_5ftransverse_98',['TJXOP_TRANSVERSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4',1,'turbojpeg.h']]],
-  ['tjxop_5fvflip_99',['TJXOP_VFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a324eddfbec53b7e691f61e56929d0d5d',1,'turbojpeg.h']]],
-  ['tjxopt_5fcopynone_100',['TJXOPT_COPYNONE',['../group___turbo_j_p_e_g.html#ga153b468cfb905d0de61706c838986fe8',1,'turbojpeg.h']]],
-  ['tjxopt_5fcrop_101',['TJXOPT_CROP',['../group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2',1,'turbojpeg.h']]],
-  ['tjxopt_5fgray_102',['TJXOPT_GRAY',['../group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589',1,'turbojpeg.h']]],
-  ['tjxopt_5fnooutput_103',['TJXOPT_NOOUTPUT',['../group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31',1,'turbojpeg.h']]],
-  ['tjxopt_5fperfect_104',['TJXOPT_PERFECT',['../group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00',1,'turbojpeg.h']]],
-  ['tjxopt_5fprogressive_105',['TJXOPT_PROGRESSIVE',['../group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026',1,'turbojpeg.h']]],
-  ['tjxopt_5ftrim_106',['TJXOPT_TRIM',['../group___turbo_j_p_e_g.html#ga319826b7eb1583c0595bbe7b95428709',1,'turbojpeg.h']]],
-  ['turbojpeg_107',['TurboJPEG',['../group___turbo_j_p_e_g.html',1,'']]]
+  ['tj3alloc_8',['tj3Alloc',['../group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d',1,'turbojpeg.h']]],
+  ['tj3compress12_9',['tj3Compress12',['../group___turbo_j_p_e_g.html#ga9a1968c384ec7abb6122830253ebf570',1,'turbojpeg.h']]],
+  ['tj3compress16_10',['tj3Compress16',['../group___turbo_j_p_e_g.html#ga77901b71d0471784f318ada31ff4e7bd',1,'turbojpeg.h']]],
+  ['tj3compress8_11',['tj3Compress8',['../group___turbo_j_p_e_g.html#ga2cc418a2dab709ad7f30f5b25905f138',1,'turbojpeg.h']]],
+  ['tj3compressfromyuv8_12',['tj3CompressFromYUV8',['../group___turbo_j_p_e_g.html#ga041c870d9c669eb3f385c78f4346c43f',1,'turbojpeg.h']]],
+  ['tj3compressfromyuvplanes8_13',['tj3CompressFromYUVPlanes8',['../group___turbo_j_p_e_g.html#gac9f5ace3e73805b476c95dda9f8d0cd0',1,'turbojpeg.h']]],
+  ['tj3decodeyuv8_14',['tj3DecodeYUV8',['../group___turbo_j_p_e_g.html#gaa1eb574f38b1c1de43a6c7aafcf68d8c',1,'turbojpeg.h']]],
+  ['tj3decodeyuvplanes8_15',['tj3DecodeYUVPlanes8',['../group___turbo_j_p_e_g.html#gad366f1915f82c1ad4e7e37ebe073ca89',1,'turbojpeg.h']]],
+  ['tj3decompress12_16',['tj3Decompress12',['../group___turbo_j_p_e_g.html#ga39b848f01781ad74a5b3941c012b6199',1,'turbojpeg.h']]],
+  ['tj3decompress16_17',['tj3Decompress16',['../group___turbo_j_p_e_g.html#gaa074e63f9beb0b3ff42b833a4049df6e',1,'turbojpeg.h']]],
+  ['tj3decompress8_18',['tj3Decompress8',['../group___turbo_j_p_e_g.html#ga1169c7c1a26ec18c9e6122cb8ae64013',1,'turbojpeg.h']]],
+  ['tj3decompressheader_19',['tj3DecompressHeader',['../group___turbo_j_p_e_g.html#ga96d2c4b3432f9d88ad14758ae240b8d1',1,'turbojpeg.h']]],
+  ['tj3decompresstoyuv8_20',['tj3DecompressToYUV8',['../group___turbo_j_p_e_g.html#ga1e6bf6a19fec3f9fa7534348879d8320',1,'turbojpeg.h']]],
+  ['tj3decompresstoyuvplanes8_21',['tj3DecompressToYUVPlanes8',['../group___turbo_j_p_e_g.html#ga934373482dbbf257f2280505b6ff4fb5',1,'turbojpeg.h']]],
+  ['tj3destroy_22',['tj3Destroy',['../group___turbo_j_p_e_g.html#ga53fbadf4560e95a65b8f5ab81703fe82',1,'turbojpeg.h']]],
+  ['tj3encodeyuv8_23',['tj3EncodeYUV8',['../group___turbo_j_p_e_g.html#ga2a8d50f130bde10f0a04030f8cc59936',1,'turbojpeg.h']]],
+  ['tj3encodeyuvplanes8_24',['tj3EncodeYUVPlanes8',['../group___turbo_j_p_e_g.html#gae2e9df38790e9bddc249d04cb158a4cf',1,'turbojpeg.h']]],
+  ['tj3free_25',['tj3Free',['../group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606',1,'turbojpeg.h']]],
+  ['tj3get_26',['tj3Get',['../group___turbo_j_p_e_g.html#ga34af9ba3183bdf0ec7c8f47bb9a4c84f',1,'turbojpeg.h']]],
+  ['tj3geterrorcode_27',['tj3GetErrorCode',['../group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd',1,'turbojpeg.h']]],
+  ['tj3geterrorstr_28',['tj3GetErrorStr',['../group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2',1,'turbojpeg.h']]],
+  ['tj3getscalingfactors_29',['tj3GetScalingFactors',['../group___turbo_j_p_e_g.html#ga74397f8e0587d4233182c72f085aaf04',1,'turbojpeg.h']]],
+  ['tj3init_30',['tj3Init',['../group___turbo_j_p_e_g.html#ga69c09d39f97ec30250ad3605ace7e5df',1,'turbojpeg.h']]],
+  ['tj3jpegbufsize_31',['tj3JPEGBufSize',['../group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4',1,'turbojpeg.h']]],
+  ['tj3loadimage12_32',['tj3LoadImage12',['../group___turbo_j_p_e_g.html#ga1f03c26892a26d4ce077ed6a4ac40e8f',1,'turbojpeg.h']]],
+  ['tj3loadimage16_33',['tj3LoadImage16',['../group___turbo_j_p_e_g.html#ga638aeba63e0ccb89d472fdbf34224cfc',1,'turbojpeg.h']]],
+  ['tj3loadimage8_34',['tj3LoadImage8',['../group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251',1,'turbojpeg.h']]],
+  ['tj3saveimage12_35',['tj3SaveImage12',['../group___turbo_j_p_e_g.html#ga7c64b5106d04267a46aad85f9714ad90',1,'turbojpeg.h']]],
+  ['tj3saveimage16_36',['tj3SaveImage16',['../group___turbo_j_p_e_g.html#ga0fd87851f4266aca24bf4594dd0c0e71',1,'turbojpeg.h']]],
+  ['tj3saveimage8_37',['tj3SaveImage8',['../group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722',1,'turbojpeg.h']]],
+  ['tj3set_38',['tj3Set',['../group___turbo_j_p_e_g.html#gaddf92640bfee3e8622218c713e77e7db',1,'turbojpeg.h']]],
+  ['tj3setcroppingregion_39',['tj3SetCroppingRegion',['../group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c',1,'turbojpeg.h']]],
+  ['tj3setscalingfactor_40',['tj3SetScalingFactor',['../group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75',1,'turbojpeg.h']]],
+  ['tj3transform_41',['tj3Transform',['../group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920',1,'turbojpeg.h']]],
+  ['tj3yuvbufsize_42',['tj3YUVBufSize',['../group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546',1,'turbojpeg.h']]],
+  ['tj3yuvplaneheight_43',['tj3YUVPlaneHeight',['../group___turbo_j_p_e_g.html#ga969767ec8180cc3edd99cf507f87299b',1,'turbojpeg.h']]],
+  ['tj3yuvplanesize_44',['tj3YUVPlaneSize',['../group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d',1,'turbojpeg.h']]],
+  ['tj3yuvplanewidth_45',['tj3YUVPlaneWidth',['../group___turbo_j_p_e_g.html#gac99d1933ede1d59fcada9a826e88eb2d',1,'turbojpeg.h']]],
+  ['tj_5fnumcs_46',['TJ_NUMCS',['../group___turbo_j_p_e_g.html#ga39f57a6fb02d9cf32e7b6890099b5a71',1,'turbojpeg.h']]],
+  ['tj_5fnumerr_47',['TJ_NUMERR',['../group___turbo_j_p_e_g.html#ga79bde1b4a3e2351e00887e47781b966e',1,'turbojpeg.h']]],
+  ['tj_5fnuminit_48',['TJ_NUMINIT',['../group___turbo_j_p_e_g.html#ga5e0e8c784295c636f0bf8dab93c4bddf',1,'turbojpeg.h']]],
+  ['tj_5fnumparam_49',['TJ_NUMPARAM',['../group___turbo_j_p_e_g.html#gaa628be5db276fc3676dfba205d45d780',1,'turbojpeg.h']]],
+  ['tj_5fnumpf_50',['TJ_NUMPF',['../group___turbo_j_p_e_g.html#ga7010a4402f54a45ba822ad8675a4655e',1,'turbojpeg.h']]],
+  ['tj_5fnumsamp_51',['TJ_NUMSAMP',['../group___turbo_j_p_e_g.html#ga5ef3d169162ce77ce348e292a0b7477c',1,'turbojpeg.h']]],
+  ['tj_5fnumxop_52',['TJ_NUMXOP',['../group___turbo_j_p_e_g.html#ga0f6dbd18adf38b7d46ac547f0f4d562c',1,'turbojpeg.h']]],
+  ['tjalphaoffset_53',['tjAlphaOffset',['../group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837',1,'turbojpeg.h']]],
+  ['tjblueoffset_54',['tjBlueOffset',['../group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea',1,'turbojpeg.h']]],
+  ['tjcs_55',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
+  ['tjcs_5fcmyk_56',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
+  ['tjcs_5fgray_57',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
+  ['tjcs_5frgb_58',['TJCS_RGB',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555',1,'turbojpeg.h']]],
+  ['tjcs_5fycbcr_59',['TJCS_YCbCr',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75',1,'turbojpeg.h']]],
+  ['tjcs_5fycck_60',['TJCS_YCCK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e',1,'turbojpeg.h']]],
+  ['tjerr_61',['TJERR',['../group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe',1,'turbojpeg.h']]],
+  ['tjerr_5ffatal_62',['TJERR_FATAL',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a',1,'turbojpeg.h']]],
+  ['tjerr_5fwarning_63',['TJERR_WARNING',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59',1,'turbojpeg.h']]],
+  ['tjgreenoffset_64',['tjGreenOffset',['../group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f',1,'turbojpeg.h']]],
+  ['tjhandle_65',['tjhandle',['../group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763',1,'turbojpeg.h']]],
+  ['tjinit_66',['TJINIT',['../group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086',1,'turbojpeg.h']]],
+  ['tjinit_5fcompress_67',['TJINIT_COMPRESS',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086aa45ac279e3dc6ffabc4b0f45864da796',1,'turbojpeg.h']]],
+  ['tjinit_5fdecompress_68',['TJINIT_DECOMPRESS',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a4b8ca1ef700699b71350700bf95c2167',1,'turbojpeg.h']]],
+  ['tjinit_5ftransform_69',['TJINIT_TRANSFORM',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a8d58a2a4c45b3e0cd349746544a6e0c2',1,'turbojpeg.h']]],
+  ['tjmcuheight_70',['tjMCUHeight',['../group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf',1,'turbojpeg.h']]],
+  ['tjmcuwidth_71',['tjMCUWidth',['../group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c',1,'turbojpeg.h']]],
+  ['tjparam_72',['TJPARAM',['../group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82',1,'turbojpeg.h']]],
+  ['tjparam_5farithmetic_73',['TJPARAM_ARITHMETIC',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7',1,'turbojpeg.h']]],
+  ['tjparam_5fbottomup_74',['TJPARAM_BOTTOMUP',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a924657172695ed6cb0b128219546fcce',1,'turbojpeg.h']]],
+  ['tjparam_5fcolorspace_75',['TJPARAM_COLORSPACE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a46a10d46309514907d0c39fcd86c324c',1,'turbojpeg.h']]],
+  ['tjparam_5fdensityunits_76',['TJPARAM_DENSITYUNITS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4c045981bd8a303521a401dbbe1df208',1,'turbojpeg.h']]],
+  ['tjparam_5ffastdct_77',['TJPARAM_FASTDCT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a6914692ac6ec5567787d592b7563f627',1,'turbojpeg.h']]],
+  ['tjparam_5ffastupsample_78',['TJPARAM_FASTUPSAMPLE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0e051ac106f7b7402b690a5daf4869c0',1,'turbojpeg.h']]],
+  ['tjparam_5fjpegheight_79',['TJPARAM_JPEGHEIGHT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f',1,'turbojpeg.h']]],
+  ['tjparam_5fjpegwidth_80',['TJPARAM_JPEGWIDTH',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8',1,'turbojpeg.h']]],
+  ['tjparam_5flossless_81',['TJPARAM_LOSSLESS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f',1,'turbojpeg.h']]],
+  ['tjparam_5flosslesspsv_82',['TJPARAM_LOSSLESSPSV',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abcc997d40e5bec84817c12b76ef84159',1,'turbojpeg.h']]],
+  ['tjparam_5flosslesspt_83',['TJPARAM_LOSSLESSPT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4a6c6f25764ecaf4231a36bff844e46a',1,'turbojpeg.h']]],
+  ['tjparam_5fnorealloc_84',['TJPARAM_NOREALLOC',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b',1,'turbojpeg.h']]],
+  ['tjparam_5foptimize_85',['TJPARAM_OPTIMIZE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6',1,'turbojpeg.h']]],
+  ['tjparam_5fprecision_86',['TJPARAM_PRECISION',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a781db82741934e8cd008d308597c59d8',1,'turbojpeg.h']]],
+  ['tjparam_5fprogressive_87',['TJPARAM_PROGRESSIVE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f',1,'turbojpeg.h']]],
+  ['tjparam_5fquality_88',['TJPARAM_QUALITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0467e8792621f2d817dc2af563d3186c',1,'turbojpeg.h']]],
+  ['tjparam_5frestartblocks_89',['TJPARAM_RESTARTBLOCKS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec',1,'turbojpeg.h']]],
+  ['tjparam_5frestartrows_90',['TJPARAM_RESTARTROWS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a714367585952fe5c863f0dba5bd37e5c',1,'turbojpeg.h']]],
+  ['tjparam_5fscanlimit_91',['TJPARAM_SCANLIMIT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ac478910e20ecf61b914f9824d80f8167',1,'turbojpeg.h']]],
+  ['tjparam_5fstoponwarning_92',['TJPARAM_STOPONWARNING',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a555e2212079fa49b30bcd2879c6c8ddb',1,'turbojpeg.h']]],
+  ['tjparam_5fsubsamp_93',['TJPARAM_SUBSAMP',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a',1,'turbojpeg.h']]],
+  ['tjparam_5fxdensity_94',['TJPARAM_XDENSITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4de5c9d7cab5be806143a43c3b0e0877',1,'turbojpeg.h']]],
+  ['tjparam_5fydensity_95',['TJPARAM_YDENSITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abda48f2df7eb9b88e2b7621efb017eba',1,'turbojpeg.h']]],
+  ['tjpf_96',['TJPF',['../group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a',1,'turbojpeg.h']]],
+  ['tjpf_5fabgr_97',['TJPF_ABGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081',1,'turbojpeg.h']]],
+  ['tjpf_5fargb_98',['TJPF_ARGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c',1,'turbojpeg.h']]],
+  ['tjpf_5fbgr_99',['TJPF_BGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aab10624437fb8ef495a0b153e65749839',1,'turbojpeg.h']]],
+  ['tjpf_5fbgra_100',['TJPF_BGRA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4',1,'turbojpeg.h']]],
+  ['tjpf_5fbgrx_101',['TJPF_BGRX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8',1,'turbojpeg.h']]],
+  ['tjpf_5fcmyk_102',['TJPF_CMYK',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b',1,'turbojpeg.h']]],
+  ['tjpf_5fgray_103',['TJPF_GRAY',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a',1,'turbojpeg.h']]],
+  ['tjpf_5frgb_104',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
+  ['tjpf_5frgba_105',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
+  ['tjpf_5frgbx_106',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
+  ['tjpf_5funknown_107',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
+  ['tjpf_5fxbgr_108',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
+  ['tjpf_5fxrgb_109',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
+  ['tjpixelsize_110',['tjPixelSize',['../group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c',1,'turbojpeg.h']]],
+  ['tjredoffset_111',['tjRedOffset',['../group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8',1,'turbojpeg.h']]],
+  ['tjregion_112',['tjregion',['../structtjregion.html',1,'']]],
+  ['tjsamp_113',['TJSAMP',['../group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074',1,'turbojpeg.h']]],
+  ['tjsamp_5f411_114',['TJSAMP_411',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2',1,'turbojpeg.h']]],
+  ['tjsamp_5f420_115',['TJSAMP_420',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737',1,'turbojpeg.h']]],
+  ['tjsamp_5f422_116',['TJSAMP_422',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a136130902cc578f11f32429b59368404',1,'turbojpeg.h']]],
+  ['tjsamp_5f440_117',['TJSAMP_440',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974',1,'turbojpeg.h']]],
+  ['tjsamp_5f441_118',['TJSAMP_441',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3351696e1dd34a083a35b6be8b90122d',1,'turbojpeg.h']]],
+  ['tjsamp_5f444_119',['TJSAMP_444',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3',1,'turbojpeg.h']]],
+  ['tjsamp_5fgray_120',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
+  ['tjsamp_5funknown_121',['TJSAMP_UNKNOWN',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074ac124fa8f6cb41147e3d670dfbdfb7173',1,'turbojpeg.h']]],
+  ['tjscaled_122',['TJSCALED',['../group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df',1,'turbojpeg.h']]],
+  ['tjscalingfactor_123',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
+  ['tjtransform_124',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#ga504805ec0161f1b505397ca0118bf8fd',1,'tjtransform():&#160;turbojpeg.h']]],
+  ['tjuncropped_125',['TJUNCROPPED',['../group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf',1,'turbojpeg.h']]],
+  ['tjunscaled_126',['TJUNSCALED',['../group___turbo_j_p_e_g.html#ga7880644a0849161ad20933536169ee19',1,'turbojpeg.h']]],
+  ['tjxop_127',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]],
+  ['tjxop_5fhflip_128',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
+  ['tjxop_5fnone_129',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
+  ['tjxop_5frot180_130',['TJXOP_ROT180',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a140952eb8dd0300accfcc22726d69692',1,'turbojpeg.h']]],
+  ['tjxop_5frot270_131',['TJXOP_ROT270',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08',1,'turbojpeg.h']]],
+  ['tjxop_5frot90_132',['TJXOP_ROT90',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a43b2bbb23bc4bd548422d43fbe9af128',1,'turbojpeg.h']]],
+  ['tjxop_5ftranspose_133',['TJXOP_TRANSPOSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a31060aed199f886afdd417f80499c32d',1,'turbojpeg.h']]],
+  ['tjxop_5ftransverse_134',['TJXOP_TRANSVERSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4',1,'turbojpeg.h']]],
+  ['tjxop_5fvflip_135',['TJXOP_VFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a324eddfbec53b7e691f61e56929d0d5d',1,'turbojpeg.h']]],
+  ['tjxopt_5farithmetic_136',['TJXOPT_ARITHMETIC',['../group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010',1,'turbojpeg.h']]],
+  ['tjxopt_5fcopynone_137',['TJXOPT_COPYNONE',['../group___turbo_j_p_e_g.html#ga153b468cfb905d0de61706c838986fe8',1,'turbojpeg.h']]],
+  ['tjxopt_5fcrop_138',['TJXOPT_CROP',['../group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2',1,'turbojpeg.h']]],
+  ['tjxopt_5fgray_139',['TJXOPT_GRAY',['../group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589',1,'turbojpeg.h']]],
+  ['tjxopt_5fnooutput_140',['TJXOPT_NOOUTPUT',['../group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31',1,'turbojpeg.h']]],
+  ['tjxopt_5foptimize_141',['TJXOPT_OPTIMIZE',['../group___turbo_j_p_e_g.html#ga6bedf37aa9e1122f3ec9f7302ca59117',1,'turbojpeg.h']]],
+  ['tjxopt_5fperfect_142',['TJXOPT_PERFECT',['../group___turbo_j_p_e_g.html#ga50e03cb5ed115330e212417429600b00',1,'turbojpeg.h']]],
+  ['tjxopt_5fprogressive_143',['TJXOPT_PROGRESSIVE',['../group___turbo_j_p_e_g.html#gad2371c80674584ecc1a7d75e564cf026',1,'turbojpeg.h']]],
+  ['tjxopt_5ftrim_144',['TJXOPT_TRIM',['../group___turbo_j_p_e_g.html#ga319826b7eb1583c0595bbe7b95428709',1,'turbojpeg.h']]],
+  ['turbojpeg_145',['TurboJPEG',['../group___turbo_j_p_e_g.html',1,'']]]
 ];
index 46e4994..7d2132b 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['w_108',['w',['../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42',1,'tjregion']]]
+  ['w_146',['w',['../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42',1,'tjregion']]]
 ];
index 157ee98..4ef2012 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['x_109',['x',['../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9',1,'tjregion']]]
+  ['x_147',['x',['../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9',1,'tjregion']]]
 ];
index 80ac522..3a72aaf 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['y_110',['y',['../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2',1,'tjregion']]]
+  ['y_148',['y',['../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2',1,'tjregion']]]
 ];
index ed057f2..ff3fb9a 100644 (file)
@@ -1,6 +1,6 @@
 var searchData=
 [
-  ['tjregion_111',['tjregion',['../structtjregion.html',1,'']]],
-  ['tjscalingfactor_112',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
-  ['tjtransform_113',['tjtransform',['../structtjtransform.html',1,'']]]
+  ['tjregion_149',['tjregion',['../structtjregion.html',1,'']]],
+  ['tjscalingfactor_150',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
+  ['tjtransform_151',['tjtransform',['../structtjtransform.html',1,'']]]
 ];
index 0e15c9a..2f372f6 100644 (file)
@@ -1,8 +1,10 @@
 var searchData=
 [
-  ['tjcs_162',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
-  ['tjerr_163',['TJERR',['../group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe',1,'turbojpeg.h']]],
-  ['tjpf_164',['TJPF',['../group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a',1,'turbojpeg.h']]],
-  ['tjsamp_165',['TJSAMP',['../group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074',1,'turbojpeg.h']]],
-  ['tjxop_166',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]]
+  ['tjcs_212',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
+  ['tjerr_213',['TJERR',['../group___turbo_j_p_e_g.html#gafbc17cfa57d0d5d11fea35ac025950fe',1,'turbojpeg.h']]],
+  ['tjinit_214',['TJINIT',['../group___turbo_j_p_e_g.html#ga3850bbee1313e752e667b4eb08b1e086',1,'turbojpeg.h']]],
+  ['tjparam_215',['TJPARAM',['../group___turbo_j_p_e_g.html#gaa0f6be63ba78278299c9f5c12031fe82',1,'turbojpeg.h']]],
+  ['tjpf_216',['TJPF',['../group___turbo_j_p_e_g.html#gac916144e26c3817ac514e64ae5d12e2a',1,'turbojpeg.h']]],
+  ['tjsamp_217',['TJSAMP',['../group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074',1,'turbojpeg.h']]],
+  ['tjxop_218',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]]
 ];
index 67c78fe..4baa519 100644 (file)
@@ -1,37 +1,65 @@
 var searchData=
 [
-  ['tjcs_5fcmyk_167',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
-  ['tjcs_5fgray_168',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
-  ['tjcs_5frgb_169',['TJCS_RGB',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555',1,'turbojpeg.h']]],
-  ['tjcs_5fycbcr_170',['TJCS_YCbCr',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75',1,'turbojpeg.h']]],
-  ['tjcs_5fycck_171',['TJCS_YCCK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e',1,'turbojpeg.h']]],
-  ['tjerr_5ffatal_172',['TJERR_FATAL',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a',1,'turbojpeg.h']]],
-  ['tjerr_5fwarning_173',['TJERR_WARNING',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59',1,'turbojpeg.h']]],
-  ['tjpf_5fabgr_174',['TJPF_ABGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081',1,'turbojpeg.h']]],
-  ['tjpf_5fargb_175',['TJPF_ARGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c',1,'turbojpeg.h']]],
-  ['tjpf_5fbgr_176',['TJPF_BGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aab10624437fb8ef495a0b153e65749839',1,'turbojpeg.h']]],
-  ['tjpf_5fbgra_177',['TJPF_BGRA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4',1,'turbojpeg.h']]],
-  ['tjpf_5fbgrx_178',['TJPF_BGRX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8',1,'turbojpeg.h']]],
-  ['tjpf_5fcmyk_179',['TJPF_CMYK',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b',1,'turbojpeg.h']]],
-  ['tjpf_5fgray_180',['TJPF_GRAY',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a',1,'turbojpeg.h']]],
-  ['tjpf_5frgb_181',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
-  ['tjpf_5frgba_182',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
-  ['tjpf_5frgbx_183',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
-  ['tjpf_5funknown_184',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
-  ['tjpf_5fxbgr_185',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
-  ['tjpf_5fxrgb_186',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
-  ['tjsamp_5f411_187',['TJSAMP_411',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2',1,'turbojpeg.h']]],
-  ['tjsamp_5f420_188',['TJSAMP_420',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737',1,'turbojpeg.h']]],
-  ['tjsamp_5f422_189',['TJSAMP_422',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a136130902cc578f11f32429b59368404',1,'turbojpeg.h']]],
-  ['tjsamp_5f440_190',['TJSAMP_440',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974',1,'turbojpeg.h']]],
-  ['tjsamp_5f444_191',['TJSAMP_444',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3',1,'turbojpeg.h']]],
-  ['tjsamp_5fgray_192',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
-  ['tjxop_5fhflip_193',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
-  ['tjxop_5fnone_194',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
-  ['tjxop_5frot180_195',['TJXOP_ROT180',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a140952eb8dd0300accfcc22726d69692',1,'turbojpeg.h']]],
-  ['tjxop_5frot270_196',['TJXOP_ROT270',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08',1,'turbojpeg.h']]],
-  ['tjxop_5frot90_197',['TJXOP_ROT90',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a43b2bbb23bc4bd548422d43fbe9af128',1,'turbojpeg.h']]],
-  ['tjxop_5ftranspose_198',['TJXOP_TRANSPOSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a31060aed199f886afdd417f80499c32d',1,'turbojpeg.h']]],
-  ['tjxop_5ftransverse_199',['TJXOP_TRANSVERSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4',1,'turbojpeg.h']]],
-  ['tjxop_5fvflip_200',['TJXOP_VFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a324eddfbec53b7e691f61e56929d0d5d',1,'turbojpeg.h']]]
+  ['tjcs_5fcmyk_219',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
+  ['tjcs_5fgray_220',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
+  ['tjcs_5frgb_221',['TJCS_RGB',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555',1,'turbojpeg.h']]],
+  ['tjcs_5fycbcr_222',['TJCS_YCbCr',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75',1,'turbojpeg.h']]],
+  ['tjcs_5fycck_223',['TJCS_YCCK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e',1,'turbojpeg.h']]],
+  ['tjerr_5ffatal_224',['TJERR_FATAL',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950feafc9cceeada13122b09e4851e3788039a',1,'turbojpeg.h']]],
+  ['tjerr_5fwarning_225',['TJERR_WARNING',['../group___turbo_j_p_e_g.html#ggafbc17cfa57d0d5d11fea35ac025950fea342dd6e2aedb47bb257b4e7568329b59',1,'turbojpeg.h']]],
+  ['tjinit_5fcompress_226',['TJINIT_COMPRESS',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086aa45ac279e3dc6ffabc4b0f45864da796',1,'turbojpeg.h']]],
+  ['tjinit_5fdecompress_227',['TJINIT_DECOMPRESS',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a4b8ca1ef700699b71350700bf95c2167',1,'turbojpeg.h']]],
+  ['tjinit_5ftransform_228',['TJINIT_TRANSFORM',['../group___turbo_j_p_e_g.html#gga3850bbee1313e752e667b4eb08b1e086a8d58a2a4c45b3e0cd349746544a6e0c2',1,'turbojpeg.h']]],
+  ['tjparam_5farithmetic_229',['TJPARAM_ARITHMETIC',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1c756757384308145602c040524aebf7',1,'turbojpeg.h']]],
+  ['tjparam_5fbottomup_230',['TJPARAM_BOTTOMUP',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a924657172695ed6cb0b128219546fcce',1,'turbojpeg.h']]],
+  ['tjparam_5fcolorspace_231',['TJPARAM_COLORSPACE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a46a10d46309514907d0c39fcd86c324c',1,'turbojpeg.h']]],
+  ['tjparam_5fdensityunits_232',['TJPARAM_DENSITYUNITS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4c045981bd8a303521a401dbbe1df208',1,'turbojpeg.h']]],
+  ['tjparam_5ffastdct_233',['TJPARAM_FASTDCT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a6914692ac6ec5567787d592b7563f627',1,'turbojpeg.h']]],
+  ['tjparam_5ffastupsample_234',['TJPARAM_FASTUPSAMPLE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0e051ac106f7b7402b690a5daf4869c0',1,'turbojpeg.h']]],
+  ['tjparam_5fjpegheight_235',['TJPARAM_JPEGHEIGHT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f76673be73f2b659440a9572a65a95f',1,'turbojpeg.h']]],
+  ['tjparam_5fjpegwidth_236',['TJPARAM_JPEGWIDTH',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a02ab77fb294a0c9061a78cd424c82dd8',1,'turbojpeg.h']]],
+  ['tjparam_5flossless_237',['TJPARAM_LOSSLESS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a249f35f0770792b19f995e603bb17c6f',1,'turbojpeg.h']]],
+  ['tjparam_5flosslesspsv_238',['TJPARAM_LOSSLESSPSV',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abcc997d40e5bec84817c12b76ef84159',1,'turbojpeg.h']]],
+  ['tjparam_5flosslesspt_239',['TJPARAM_LOSSLESSPT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4a6c6f25764ecaf4231a36bff844e46a',1,'turbojpeg.h']]],
+  ['tjparam_5fnorealloc_240',['TJPARAM_NOREALLOC',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ae64ffb358bc7b194fd48e0f27750b29b',1,'turbojpeg.h']]],
+  ['tjparam_5foptimize_241',['TJPARAM_OPTIMIZE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a8f0af9afc0b36443751f9ee82b760aa6',1,'turbojpeg.h']]],
+  ['tjparam_5fprecision_242',['TJPARAM_PRECISION',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a781db82741934e8cd008d308597c59d8',1,'turbojpeg.h']]],
+  ['tjparam_5fprogressive_243',['TJPARAM_PROGRESSIVE',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a1716f242b3859905b4a317dae8cfb75f',1,'turbojpeg.h']]],
+  ['tjparam_5fquality_244',['TJPARAM_QUALITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a0467e8792621f2d817dc2af563d3186c',1,'turbojpeg.h']]],
+  ['tjparam_5frestartblocks_245',['TJPARAM_RESTARTBLOCKS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a343c72883b7160f23f3ef46fc548a0ec',1,'turbojpeg.h']]],
+  ['tjparam_5frestartrows_246',['TJPARAM_RESTARTROWS',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a714367585952fe5c863f0dba5bd37e5c',1,'turbojpeg.h']]],
+  ['tjparam_5fscanlimit_247',['TJPARAM_SCANLIMIT',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82ac478910e20ecf61b914f9824d80f8167',1,'turbojpeg.h']]],
+  ['tjparam_5fstoponwarning_248',['TJPARAM_STOPONWARNING',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a555e2212079fa49b30bcd2879c6c8ddb',1,'turbojpeg.h']]],
+  ['tjparam_5fsubsamp_249',['TJPARAM_SUBSAMP',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a2a3494a8215d3de4fdbaeb2ba6f6b03a',1,'turbojpeg.h']]],
+  ['tjparam_5fxdensity_250',['TJPARAM_XDENSITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82a4de5c9d7cab5be806143a43c3b0e0877',1,'turbojpeg.h']]],
+  ['tjparam_5fydensity_251',['TJPARAM_YDENSITY',['../group___turbo_j_p_e_g.html#ggaa0f6be63ba78278299c9f5c12031fe82abda48f2df7eb9b88e2b7621efb017eba',1,'turbojpeg.h']]],
+  ['tjpf_5fabgr_252',['TJPF_ABGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa1ba1a7f1631dbeaa49a0a85fc4a40081',1,'turbojpeg.h']]],
+  ['tjpf_5fargb_253',['TJPF_ARGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aae8f846ed9d9de99b6e1dfe448848765c',1,'turbojpeg.h']]],
+  ['tjpf_5fbgr_254',['TJPF_BGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aab10624437fb8ef495a0b153e65749839',1,'turbojpeg.h']]],
+  ['tjpf_5fbgra_255',['TJPF_BGRA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aac037ff1845cf9b74bb81a3659c2b9fb4',1,'turbojpeg.h']]],
+  ['tjpf_5fbgrx_256',['TJPF_BGRX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa2a1fbf569ca79897eae886e3376ca4c8',1,'turbojpeg.h']]],
+  ['tjpf_5fcmyk_257',['TJPF_CMYK',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7f5100ec44c91994e243f1cf55553f8b',1,'turbojpeg.h']]],
+  ['tjpf_5fgray_258',['TJPF_GRAY',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa5431b54b015337705f13118073711a1a',1,'turbojpeg.h']]],
+  ['tjpf_5frgb_259',['TJPF_RGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa7ce93230bff449518ce387c17e6ed37c',1,'turbojpeg.h']]],
+  ['tjpf_5frgba_260',['TJPF_RGBA',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa88d2e88fab67f6503cf972e14851cc12',1,'turbojpeg.h']]],
+  ['tjpf_5frgbx_261',['TJPF_RGBX',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa83973bebb7e2dc6fa8bae89ff3f42e01',1,'turbojpeg.h']]],
+  ['tjpf_5funknown_262',['TJPF_UNKNOWN',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aa84c1a6cead7952998e2fb895844a21ed',1,'turbojpeg.h']]],
+  ['tjpf_5fxbgr_263',['TJPF_XBGR',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aaf6603b27147de47e212e75dac027b2af',1,'turbojpeg.h']]],
+  ['tjpf_5fxrgb_264',['TJPF_XRGB',['../group___turbo_j_p_e_g.html#ggac916144e26c3817ac514e64ae5d12e2aadae996905efcfa3b42a0bb3bea7f9d84',1,'turbojpeg.h']]],
+  ['tjsamp_5f411_265',['TJSAMP_411',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a28ec62575e5ea295c3fde3001dc628e2',1,'turbojpeg.h']]],
+  ['tjsamp_5f420_266',['TJSAMP_420',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a63085dbf683cfe39e513cdb6343e3737',1,'turbojpeg.h']]],
+  ['tjsamp_5f422_267',['TJSAMP_422',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a136130902cc578f11f32429b59368404',1,'turbojpeg.h']]],
+  ['tjsamp_5f440_268',['TJSAMP_440',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074accf740e6f3aa6ba20ba922cad13cb974',1,'turbojpeg.h']]],
+  ['tjsamp_5f441_269',['TJSAMP_441',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3351696e1dd34a083a35b6be8b90122d',1,'turbojpeg.h']]],
+  ['tjsamp_5f444_270',['TJSAMP_444',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074afb8da4f44197837bdec0a4f593dacae3',1,'turbojpeg.h']]],
+  ['tjsamp_5fgray_271',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
+  ['tjsamp_5funknown_272',['TJSAMP_UNKNOWN',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074ac124fa8f6cb41147e3d670dfbdfb7173',1,'turbojpeg.h']]],
+  ['tjxop_5fhflip_273',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
+  ['tjxop_5fnone_274',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
+  ['tjxop_5frot180_275',['TJXOP_ROT180',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a140952eb8dd0300accfcc22726d69692',1,'turbojpeg.h']]],
+  ['tjxop_5frot270_276',['TJXOP_ROT270',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a3064ee5dfb7f032df332818587567a08',1,'turbojpeg.h']]],
+  ['tjxop_5frot90_277',['TJXOP_ROT90',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a43b2bbb23bc4bd548422d43fbe9af128',1,'turbojpeg.h']]],
+  ['tjxop_5ftranspose_278',['TJXOP_TRANSPOSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a31060aed199f886afdd417f80499c32d',1,'turbojpeg.h']]],
+  ['tjxop_5ftransverse_279',['TJXOP_TRANSVERSE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866af3b14d488aea6ece9e5b3df73a74d6a4',1,'turbojpeg.h']]],
+  ['tjxop_5fvflip_280',['TJXOP_VFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866a324eddfbec53b7e691f61e56929d0d5d',1,'turbojpeg.h']]]
 ];
index 4a9ea5b..18f7e3f 100644 (file)
@@ -1,31 +1,41 @@
 var searchData=
 [
-  ['tjalloc_114',['tjAlloc',['../group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83',1,'turbojpeg.h']]],
-  ['tjbufsize_115',['tjBufSize',['../group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90',1,'turbojpeg.h']]],
-  ['tjbufsizeyuv2_116',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#ga2be2b9969d4df9ecce9b05deed273194',1,'turbojpeg.h']]],
-  ['tjcompress2_117',['tjCompress2',['../group___turbo_j_p_e_g.html#gafbdce0112fd78fd38efae841443a9bcf',1,'turbojpeg.h']]],
-  ['tjcompressfromyuv_118',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga7622a459b79aa1007e005b58783f875b',1,'turbojpeg.h']]],
-  ['tjcompressfromyuvplanes_119',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#ga29ec5dfbd2d84b8724e951d6fa0d5d9e',1,'turbojpeg.h']]],
-  ['tjdecodeyuv_120',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga70abbf38f77a26fd6da8813bef96f695',1,'turbojpeg.h']]],
-  ['tjdecodeyuvplanes_121',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga10e837c07fa9d25770565b237d3898d9',1,'turbojpeg.h']]],
-  ['tjdecompress2_122',['tjDecompress2',['../group___turbo_j_p_e_g.html#gae9eccef8b682a48f43a9117c231ed013',1,'turbojpeg.h']]],
-  ['tjdecompressheader3_123',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#ga0595681096bba7199cc6f3533cb25f77',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuv2_124',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga04d1e839ff9a0860dd1475cff78d3364',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuvplanes_125',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#gaa59f901a5258ada5bd0185ad59368540',1,'turbojpeg.h']]],
-  ['tjdestroy_126',['tjDestroy',['../group___turbo_j_p_e_g.html#ga75f355fa27225ba1a4ee392c852394d2',1,'turbojpeg.h']]],
-  ['tjencodeyuv3_127',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#gac519b922cdf446e97d0cdcba513636bf',1,'turbojpeg.h']]],
-  ['tjencodeyuvplanes_128',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#gae2d04c72457fe7f4d60cf78ab1b1feb1',1,'turbojpeg.h']]],
-  ['tjfree_129',['tjFree',['../group___turbo_j_p_e_g.html#gaea863d2da0cdb609563aabdf9196514b',1,'turbojpeg.h']]],
-  ['tjgeterrorcode_130',['tjGetErrorCode',['../group___turbo_j_p_e_g.html#ga414feeffbf860ebd31c745df203de410',1,'turbojpeg.h']]],
-  ['tjgeterrorstr2_131',['tjGetErrorStr2',['../group___turbo_j_p_e_g.html#ga1ead8574f9f39fbafc6b497124e7aafa',1,'turbojpeg.h']]],
-  ['tjgetscalingfactors_132',['tjGetScalingFactors',['../group___turbo_j_p_e_g.html#gac3854476006b10787bd128f7ede48057',1,'turbojpeg.h']]],
-  ['tjinitcompress_133',['tjInitCompress',['../group___turbo_j_p_e_g.html#ga9d63a05fc6d813f4aae06107041a37e8',1,'turbojpeg.h']]],
-  ['tjinitdecompress_134',['tjInitDecompress',['../group___turbo_j_p_e_g.html#ga52300eac3f3d9ef4bab303bc244f62d3',1,'turbojpeg.h']]],
-  ['tjinittransform_135',['tjInitTransform',['../group___turbo_j_p_e_g.html#ga928beff6ac248ceadf01089fc6b41957',1,'turbojpeg.h']]],
-  ['tjloadimage_136',['tjLoadImage',['../group___turbo_j_p_e_g.html#gaffbd83c375e79f5db4b5c5d8ad4466e7',1,'turbojpeg.h']]],
-  ['tjplaneheight_137',['tjPlaneHeight',['../group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f',1,'turbojpeg.h']]],
-  ['tjplanesizeyuv_138',['tjPlaneSizeYUV',['../group___turbo_j_p_e_g.html#gab4ab7b24f6e797d79abaaa670373961d',1,'turbojpeg.h']]],
-  ['tjplanewidth_139',['tjPlaneWidth',['../group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1',1,'turbojpeg.h']]],
-  ['tjsaveimage_140',['tjSaveImage',['../group___turbo_j_p_e_g.html#ga6f445b22d8933ae4815b3370a538d879',1,'turbojpeg.h']]],
-  ['tjtransform_141',['tjTransform',['../group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25',1,'turbojpeg.h']]]
+  ['tj3alloc_152',['tj3Alloc',['../group___turbo_j_p_e_g.html#gab40a0b231122f536e503e3394569a68d',1,'turbojpeg.h']]],
+  ['tj3compress12_153',['tj3Compress12',['../group___turbo_j_p_e_g.html#ga9a1968c384ec7abb6122830253ebf570',1,'turbojpeg.h']]],
+  ['tj3compress16_154',['tj3Compress16',['../group___turbo_j_p_e_g.html#ga77901b71d0471784f318ada31ff4e7bd',1,'turbojpeg.h']]],
+  ['tj3compress8_155',['tj3Compress8',['../group___turbo_j_p_e_g.html#ga2cc418a2dab709ad7f30f5b25905f138',1,'turbojpeg.h']]],
+  ['tj3compressfromyuv8_156',['tj3CompressFromYUV8',['../group___turbo_j_p_e_g.html#ga041c870d9c669eb3f385c78f4346c43f',1,'turbojpeg.h']]],
+  ['tj3compressfromyuvplanes8_157',['tj3CompressFromYUVPlanes8',['../group___turbo_j_p_e_g.html#gac9f5ace3e73805b476c95dda9f8d0cd0',1,'turbojpeg.h']]],
+  ['tj3decodeyuv8_158',['tj3DecodeYUV8',['../group___turbo_j_p_e_g.html#gaa1eb574f38b1c1de43a6c7aafcf68d8c',1,'turbojpeg.h']]],
+  ['tj3decodeyuvplanes8_159',['tj3DecodeYUVPlanes8',['../group___turbo_j_p_e_g.html#gad366f1915f82c1ad4e7e37ebe073ca89',1,'turbojpeg.h']]],
+  ['tj3decompress12_160',['tj3Decompress12',['../group___turbo_j_p_e_g.html#ga39b848f01781ad74a5b3941c012b6199',1,'turbojpeg.h']]],
+  ['tj3decompress16_161',['tj3Decompress16',['../group___turbo_j_p_e_g.html#gaa074e63f9beb0b3ff42b833a4049df6e',1,'turbojpeg.h']]],
+  ['tj3decompress8_162',['tj3Decompress8',['../group___turbo_j_p_e_g.html#ga1169c7c1a26ec18c9e6122cb8ae64013',1,'turbojpeg.h']]],
+  ['tj3decompressheader_163',['tj3DecompressHeader',['../group___turbo_j_p_e_g.html#ga96d2c4b3432f9d88ad14758ae240b8d1',1,'turbojpeg.h']]],
+  ['tj3decompresstoyuv8_164',['tj3DecompressToYUV8',['../group___turbo_j_p_e_g.html#ga1e6bf6a19fec3f9fa7534348879d8320',1,'turbojpeg.h']]],
+  ['tj3decompresstoyuvplanes8_165',['tj3DecompressToYUVPlanes8',['../group___turbo_j_p_e_g.html#ga934373482dbbf257f2280505b6ff4fb5',1,'turbojpeg.h']]],
+  ['tj3destroy_166',['tj3Destroy',['../group___turbo_j_p_e_g.html#ga53fbadf4560e95a65b8f5ab81703fe82',1,'turbojpeg.h']]],
+  ['tj3encodeyuv8_167',['tj3EncodeYUV8',['../group___turbo_j_p_e_g.html#ga2a8d50f130bde10f0a04030f8cc59936',1,'turbojpeg.h']]],
+  ['tj3encodeyuvplanes8_168',['tj3EncodeYUVPlanes8',['../group___turbo_j_p_e_g.html#gae2e9df38790e9bddc249d04cb158a4cf',1,'turbojpeg.h']]],
+  ['tj3free_169',['tj3Free',['../group___turbo_j_p_e_g.html#gaddb84fb6c81769e9faa0f5a63b296606',1,'turbojpeg.h']]],
+  ['tj3get_170',['tj3Get',['../group___turbo_j_p_e_g.html#ga34af9ba3183bdf0ec7c8f47bb9a4c84f',1,'turbojpeg.h']]],
+  ['tj3geterrorcode_171',['tj3GetErrorCode',['../group___turbo_j_p_e_g.html#gab8c8279f1415fe425ff30dbbc56013bd',1,'turbojpeg.h']]],
+  ['tj3geterrorstr_172',['tj3GetErrorStr',['../group___turbo_j_p_e_g.html#gaf2aab0e6dbb3edc57646b0fec25e8bb2',1,'turbojpeg.h']]],
+  ['tj3getscalingfactors_173',['tj3GetScalingFactors',['../group___turbo_j_p_e_g.html#ga74397f8e0587d4233182c72f085aaf04',1,'turbojpeg.h']]],
+  ['tj3init_174',['tj3Init',['../group___turbo_j_p_e_g.html#ga69c09d39f97ec30250ad3605ace7e5df',1,'turbojpeg.h']]],
+  ['tj3jpegbufsize_175',['tj3JPEGBufSize',['../group___turbo_j_p_e_g.html#gac6285e58e35a35d871d7162ec5a929c4',1,'turbojpeg.h']]],
+  ['tj3loadimage12_176',['tj3LoadImage12',['../group___turbo_j_p_e_g.html#ga1f03c26892a26d4ce077ed6a4ac40e8f',1,'turbojpeg.h']]],
+  ['tj3loadimage16_177',['tj3LoadImage16',['../group___turbo_j_p_e_g.html#ga638aeba63e0ccb89d472fdbf34224cfc',1,'turbojpeg.h']]],
+  ['tj3loadimage8_178',['tj3LoadImage8',['../group___turbo_j_p_e_g.html#ga565aaae7be3f8ca9099b56655c893251',1,'turbojpeg.h']]],
+  ['tj3saveimage12_179',['tj3SaveImage12',['../group___turbo_j_p_e_g.html#ga7c64b5106d04267a46aad85f9714ad90',1,'turbojpeg.h']]],
+  ['tj3saveimage16_180',['tj3SaveImage16',['../group___turbo_j_p_e_g.html#ga0fd87851f4266aca24bf4594dd0c0e71',1,'turbojpeg.h']]],
+  ['tj3saveimage8_181',['tj3SaveImage8',['../group___turbo_j_p_e_g.html#gaa4ec838988e469cc15618e4690cc8722',1,'turbojpeg.h']]],
+  ['tj3set_182',['tj3Set',['../group___turbo_j_p_e_g.html#gaddf92640bfee3e8622218c713e77e7db',1,'turbojpeg.h']]],
+  ['tj3setcroppingregion_183',['tj3SetCroppingRegion',['../group___turbo_j_p_e_g.html#gaa49c7bd4c9431667a043cfc93388ba1c',1,'turbojpeg.h']]],
+  ['tj3setscalingfactor_184',['tj3SetScalingFactor',['../group___turbo_j_p_e_g.html#ga89da17ee1e43ff423382cbc145803c75',1,'turbojpeg.h']]],
+  ['tj3transform_185',['tj3Transform',['../group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920',1,'turbojpeg.h']]],
+  ['tj3yuvbufsize_186',['tj3YUVBufSize',['../group___turbo_j_p_e_g.html#gaaebaa16973a0f550a66eca5765ed0546',1,'turbojpeg.h']]],
+  ['tj3yuvplaneheight_187',['tj3YUVPlaneHeight',['../group___turbo_j_p_e_g.html#ga969767ec8180cc3edd99cf507f87299b',1,'turbojpeg.h']]],
+  ['tj3yuvplanesize_188',['tj3YUVPlaneSize',['../group___turbo_j_p_e_g.html#gacc19d265edce76b46146f59579f9438d',1,'turbojpeg.h']]],
+  ['tj3yuvplanewidth_189',['tj3YUVPlaneWidth',['../group___turbo_j_p_e_g.html#gac99d1933ede1d59fcada9a826e88eb2d',1,'turbojpeg.h']]]
 ];
index b4e000d..97bded0 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['turbojpeg_201',['TurboJPEG',['../group___turbo_j_p_e_g.html',1,'']]]
+  ['turbojpeg_281',['TurboJPEG',['../group___turbo_j_p_e_g.html',1,'']]]
 ];
index bad1a20..968490f 100644 (file)
@@ -1,5 +1,5 @@
 var searchData=
 [
-  ['tjhandle_160',['tjhandle',['../group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763',1,'turbojpeg.h']]],
-  ['tjtransform_161',['tjtransform',['../group___turbo_j_p_e_g.html#ga504805ec0161f1b505397ca0118bf8fd',1,'turbojpeg.h']]]
+  ['tjhandle_210',['tjhandle',['../group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763',1,'turbojpeg.h']]],
+  ['tjtransform_211',['tjtransform',['../group___turbo_j_p_e_g.html#ga504805ec0161f1b505397ca0118bf8fd',1,'turbojpeg.h']]]
 ];
index 9ed036c..40a95a8 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['customfilter_142',['customFilter',['../structtjtransform.html#afd7fc262df33f741e120ef4183202ef5',1,'tjtransform']]]
+  ['customfilter_190',['customFilter',['../structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2',1,'tjtransform']]]
 ];
index 3dc2108..9113a24 100644 (file)
@@ -1,5 +1,5 @@
 var searchData=
 [
-  ['data_143',['data',['../structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3',1,'tjtransform']]],
-  ['denom_144',['denom',['../structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3',1,'tjscalingfactor']]]
+  ['data_191',['data',['../structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3',1,'tjtransform']]],
+  ['denom_192',['denom',['../structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3',1,'tjscalingfactor']]]
 ];
index f0d8327..a907b81 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['h_145',['h',['../structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115',1,'tjregion']]]
+  ['h_193',['h',['../structtjregion.html#aecefc45a26f4d8b60dd4d825c1710115',1,'tjregion']]]
 ];
index e719258..7b5a616 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['num_146',['num',['../structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec',1,'tjscalingfactor']]]
+  ['num_194',['num',['../structtjscalingfactor.html#a9b011e57f981ee23083e2c1aa5e640ec',1,'tjscalingfactor']]]
 ];
index 2650623..c2bfaa8 100644 (file)
@@ -1,5 +1,5 @@
 var searchData=
 [
-  ['op_147',['op',['../structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498',1,'tjtransform']]],
-  ['options_148',['options',['../structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6',1,'tjtransform']]]
+  ['op_195',['op',['../structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498',1,'tjtransform']]],
+  ['options_196',['options',['../structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6',1,'tjtransform']]]
 ];
index 2639dfd..0ae92ea 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['r_149',['r',['../structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf',1,'tjtransform']]]
+  ['r_197',['r',['../structtjtransform.html#ac324e5e442abec8a961e5bf219db12cf',1,'tjtransform']]]
 ];
index 50b3fd7..2e7c0b3 100644 (file)
@@ -1,10 +1,12 @@
 var searchData=
 [
-  ['tjalphaoffset_150',['tjAlphaOffset',['../group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837',1,'turbojpeg.h']]],
-  ['tjblueoffset_151',['tjBlueOffset',['../group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea',1,'turbojpeg.h']]],
-  ['tjgreenoffset_152',['tjGreenOffset',['../group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f',1,'turbojpeg.h']]],
-  ['tjmcuheight_153',['tjMCUHeight',['../group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf',1,'turbojpeg.h']]],
-  ['tjmcuwidth_154',['tjMCUWidth',['../group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c',1,'turbojpeg.h']]],
-  ['tjpixelsize_155',['tjPixelSize',['../group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c',1,'turbojpeg.h']]],
-  ['tjredoffset_156',['tjRedOffset',['../group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8',1,'turbojpeg.h']]]
+  ['tjalphaoffset_198',['tjAlphaOffset',['../group___turbo_j_p_e_g.html#ga5af0ab065feefd526debf1e20c43e837',1,'turbojpeg.h']]],
+  ['tjblueoffset_199',['tjBlueOffset',['../group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea',1,'turbojpeg.h']]],
+  ['tjgreenoffset_200',['tjGreenOffset',['../group___turbo_j_p_e_g.html#ga82d6e35da441112a411da41923c0ba2f',1,'turbojpeg.h']]],
+  ['tjmcuheight_201',['tjMCUHeight',['../group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf',1,'turbojpeg.h']]],
+  ['tjmcuwidth_202',['tjMCUWidth',['../group___turbo_j_p_e_g.html#ga9e61e7cd47a15a173283ba94e781308c',1,'turbojpeg.h']]],
+  ['tjpixelsize_203',['tjPixelSize',['../group___turbo_j_p_e_g.html#gad77cf8fe5b2bfd3cb3f53098146abb4c',1,'turbojpeg.h']]],
+  ['tjredoffset_204',['tjRedOffset',['../group___turbo_j_p_e_g.html#gadd9b446742ac8a3923f7992c7988fea8',1,'turbojpeg.h']]],
+  ['tjuncropped_205',['TJUNCROPPED',['../group___turbo_j_p_e_g.html#ga6f192ad58a5a5802e145149d83c643bf',1,'turbojpeg.h']]],
+  ['tjunscaled_206',['TJUNSCALED',['../group___turbo_j_p_e_g.html#ga7880644a0849161ad20933536169ee19',1,'turbojpeg.h']]]
 ];
index cd4a680..c8c66b6 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['w_157',['w',['../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42',1,'tjregion']]]
+  ['w_207',['w',['../structtjregion.html#ab6eb73ceef584fc23c8c8097926dce42',1,'tjregion']]]
 ];
index 61434f0..5f81e56 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['x_158',['x',['../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9',1,'tjregion']]]
+  ['x_208',['x',['../structtjregion.html#a4b6a37a93997091b26a75831fa291ad9',1,'tjregion']]]
 ];
index 32719d4..bb57e20 100644 (file)
@@ -1,4 +1,4 @@
 var searchData=
 [
-  ['y_159',['y',['../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2',1,'tjregion']]]
+  ['y_209',['y',['../structtjregion.html#a7b3e0c24cfe87acc80e334cafdcf22c2',1,'tjregion']]]
 ];
index 72d49d2..e678584 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
@@ -157,7 +157,7 @@ Data Fields</h2></td></tr>
 </div><div class="memdoc">
 
 <p>The upper boundary of the cropping region. </p>
-<p>This must be evenly divisible by the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) </p>
+<p>For lossless transformation, this must be evenly divisible by the MCU block height (see <a class="el" href="group___turbo_j_p_e_g.html#gabd247bb9fecb393eca57366feb8327bf" title="MCU block height (in pixels) for a given level of chrominance subsampling.">tjMCUHeight</a>.) </p>
 
 </div>
 </div>
index 1606a02..818dfbd 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
index ba78980..9facd85 100644 (file)
@@ -23,7 +23,7 @@
  <tr style="height: 56px;">
   <td id="projectalign" style="padding-left: 0.5em;">
    <div id="projectname">TurboJPEG
-   &#160;<span id="projectnumber">2.1.4</span>
+   &#160;<span id="projectnumber">3</span>
    </div>
   </td>
  </tr>
@@ -84,26 +84,26 @@ Data Fields</h2></td></tr>
 <tr class="memdesc:a2525aab4ba6978a1c273f74fef50e498"><td class="mdescLeft">&#160;</td><td class="mdescRight">One of the <a class="el" href="group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866">transform operations</a>.  <a href="structtjtransform.html#a2525aab4ba6978a1c273f74fef50e498">More...</a><br /></td></tr>
 <tr class="separator:a2525aab4ba6978a1c273f74fef50e498"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ac0e74655baa4402209a21e1ae481c8f6"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">options</a></td></tr>
-<tr class="memdesc:ac0e74655baa4402209a21e1ae481c8f6"><td class="mdescLeft">&#160;</td><td class="mdescRight">The bitwise OR of one of more of the <a class="el" href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2">transform options</a>.  <a href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">More...</a><br /></td></tr>
+<tr class="memdesc:ac0e74655baa4402209a21e1ae481c8f6"><td class="mdescLeft">&#160;</td><td class="mdescRight">The bitwise OR of one of more of the <a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010">transform options</a>.  <a href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">More...</a><br /></td></tr>
 <tr class="separator:ac0e74655baa4402209a21e1ae481c8f6"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memItemLeft" align="right" valign="top">void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">data</a></td></tr>
 <tr class="memdesc:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="mdescLeft">&#160;</td><td class="mdescRight">Arbitrary data that can be accessed within the body of the callback function.  <a href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">More...</a><br /></td></tr>
 <tr class="separator:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:afd7fc262df33f741e120ef4183202ef5"><td class="memItemLeft" align="right" valign="top">int(*&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">customFilter</a> )(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td></tr>
-<tr class="memdesc:afd7fc262df33f741e120ef4183202ef5"><td class="mdescLeft">&#160;</td><td class="mdescRight">A callback function that can be used to modify the DCT coefficients after they are losslessly transformed but before they are transcoded to a new JPEG image.  <a href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">More...</a><br /></td></tr>
-<tr class="separator:afd7fc262df33f741e120ef4183202ef5"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="memItemLeft" align="right" valign="top">int(*&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">customFilter</a> )(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentID, int transformID, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td></tr>
+<tr class="memdesc:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="mdescLeft">&#160;</td><td class="mdescRight">A callback function that can be used to modify the DCT coefficients after they are losslessly transformed but before they are transcoded to a new JPEG image.  <a href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">More...</a><br /></td></tr>
+<tr class="separator:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
 </table>
 <a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
 <div class="textblock"><p>Lossless transform. </p>
 </div><h2 class="groupheader">Field Documentation</h2>
-<a id="afd7fc262df33f741e120ef4183202ef5"></a>
-<h2 class="memtitle"><span class="permalink"><a href="#afd7fc262df33f741e120ef4183202ef5">&#9670;&nbsp;</a></span>customFilter</h2>
+<a id="a0dc7697d59a7abe48afc629e96cbc1d2"></a>
+<h2 class="memtitle"><span class="permalink"><a href="#a0dc7697d59a7abe48afc629e96cbc1d2">&#9670;&nbsp;</a></span>customFilter</h2>
 
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
         <tr>
-          <td class="memname">int(* tjtransform::customFilter) (short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td>
+          <td class="memname">int(* tjtransform::customFilter) (short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentID, int transformID, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td>
         </tr>
       </table>
 </div><div class="memdoc">
@@ -115,8 +115,8 @@ Data Fields</h2></td></tr>
     <tr><td class="paramname">coeffs</td><td>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.)</td></tr>
     <tr><td class="paramname">arrayRegion</td><td><a class="el" href="structtjregion.html" title="Cropping region.">tjregion</a> structure containing the width and height of the array pointed to by <code>coeffs</code> 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.</td></tr>
     <tr><td class="paramname">planeRegion</td><td><a class="el" href="structtjregion.html" title="Cropping region.">tjregion</a> structure containing the width and height of the component plane to which <code>coeffs</code> belongs</td></tr>
-    <tr><td class="paramname">componentID</td><td>ID number of the component plane to which <code>coeffs</code> belongs (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in typical JPEG images.)</td></tr>
-    <tr><td class="paramname">transformID</td><td>ID number of the transformed image to which <code>coeffs</code> belongs. This is the same as the index of the transform in the <code>transforms</code> array that was passed to <a class="el" href="group___turbo_j_p_e_g.html#ga9cb8abf4cc91881e04a0329b2270be25" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>.</td></tr>
+    <tr><td class="paramname">componentID</td><td>ID number of the component plane to which <code>coeffs</code> belongs. (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in typical JPEG images.)</td></tr>
+    <tr><td class="paramname">transformID</td><td>ID number of the transformed image to which <code>coeffs</code> belongs. This is the same as the index of the transform in the <code>transforms</code> array that was passed to <a class="el" href="group___turbo_j_p_e_g.html#gaff23ba1dcabed456794b844791613920" title="Losslessly transform a JPEG image into another JPEG image.">tj3Transform()</a>.</td></tr>
     <tr><td class="paramname">transform</td><td>a pointer to a <a class="el" href="structtjtransform.html" title="Lossless transform.">tjtransform</a> structure that specifies the parameters and/or cropping region for this transform</td></tr>
   </table>
   </dd>
@@ -169,7 +169,7 @@ Data Fields</h2></td></tr>
       </table>
 </div><div class="memdoc">
 
-<p>The bitwise OR of one of more of the <a class="el" href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2">transform options</a>. </p>
+<p>The bitwise OR of one of more of the <a class="el" href="group___turbo_j_p_e_g.html#gaecaaa3b7e2af812592c015d83207f010">transform options</a>. </p>
 
 </div>
 </div>
index 16708b0..1309a05 100644 (file)
@@ -1,5 +1,5 @@
 PROJECT_NAME = TurboJPEG
-PROJECT_NUMBER = 2.1.4
+PROJECT_NUMBER = 3
 OUTPUT_DIRECTORY = doc/
 USE_WINDOWS_ENCODING = NO
 OPTIMIZE_OUTPUT_FOR_C = YES
similarity index 59%
rename from example.txt
rename to example.c
index d473aed..4a82695 100644 (file)
+++ b/example.c
@@ -1,33 +1,41 @@
 /*
- * example.txt
+ * example.c
  *
- * This file illustrates how to use the IJG code as a subroutine library
- * to read or write JPEG image files.  You should look at this code in
- * conjunction with the documentation file libjpeg.txt.
+ * 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-2023, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
  *
- * This code will not do anything useful as-is, but it may be helpful as a
- * skeleton for constructing routines that call the JPEG library.
+ * 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.
  */
 
-/* This example was part of the original libjpeg documentation and has been
- * unchanged since 1994.  It is, as described in libjpeg.txt, "heavily
- * commented skeleton code for calling the JPEG library."  It is not meant to
- * be compiled as a standalone program, since it has no main() function and
- * does not compress from/decompress to a real image buffer (corollary:
- * put_scanline_someplace() is not a real function.)  First-time users of
- * libjpeg-turbo would be better served by looking at tjexample.c, which uses
- * the more straightforward TurboJPEG API, or at cjpeg.c and djpeg.c, which are
- * examples of libjpeg API usage that can be (and are) compiled into standalone
- * programs.  Note that this example, as well as the examples in cjpeg.c and
- * djpeg.c, interleave disk I/O with JPEG compression/decompression, so none of
- * these examples is suitable for benchmarking purposes.
+/* First-time users of libjpeg-turbo might be better served by looking at
+ * tjexample.c, which uses the more straightforward TurboJPEG API.  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.
@@ -38,6 +46,7 @@
  */
 
 #include "jpeglib.h"
+#include "jerror.h"
 
 /*
  * <setjmp.h> is used for the optional error recovery mechanism shown in
  *
  * 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).
- * 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.
+ * 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
  * RGB color and is described by:
  */
 
-extern JSAMPLE *image_buffer;   /* Points to large array of R,G,B-order data */
-extern int image_height;        /* Number of rows in image */
-extern int image_width;         /* Number of columns in image */
+#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
- * and a compression quality factor are passed in.
+ * Sample routine for JPEG compression.  We assume that the target file name,
+ * a compression quality factor, and a data precision are passed in.
  */
 
-GLOBAL(void)
-write_JPEG_file(char *filename, int quality)
+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).
@@ -103,8 +111,15 @@ write_JPEG_file(char *filename, int quality)
   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 */
 
@@ -125,10 +140,8 @@ write_JPEG_file(char *filename, int quality)
    * 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) {
-    fprintf(stderr, "can't open %s\n", filename);
-    exit(1);
-  }
+  if ((outfile = fopen(filename, "wb")) == NULL)
+    ERREXIT(&cinfo, JERR_FILE_WRITE);
   jpeg_stdio_dest(&cinfo, outfile);
 
   /* Step 3: set parameters for compression */
@@ -136,10 +149,11 @@ write_JPEG_file(char *filename, int quality)
   /* First we supply a description of the input image.
    * Four fields of the cinfo struct must be filled in:
    */
-  cinfo.image_width = image_width;      /* image width and height, in pixels */
-  cinfo.image_height = image_height;
+  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.)
@@ -149,6 +163,8 @@ write_JPEG_file(char *filename, int quality)
    * 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 */
 
@@ -157,7 +173,48 @@ write_JPEG_file(char *filename, int quality)
    */
   jpeg_start_compress(&cinfo, TRUE);
 
-  /* Step 5: while (scan lines remain to be written) */
+  /* 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
@@ -165,24 +222,33 @@ write_JPEG_file(char *filename, int quality)
    * To keep things simple, we pass one scanline per call; you can pass
    * more if you wish, though.
    */
-  row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
-
-  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 * row_stride];
-    (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
+  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 6: Finish compression */
+  /* Step 7: Finish compression */
 
   jpeg_finish_compress(&cinfo);
   /* After finish_compress, we can close the output file. */
   fclose(outfile);
 
-  /* Step 7: release JPEG compression object */
+  /* Step 8: release JPEG compression object */
 
   /* This is an important step since it will release a good deal of memory. */
   jpeg_destroy_compress(&cinfo);
@@ -231,10 +297,11 @@ write_JPEG_file(char *filename, int quality)
  * 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 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.
+ * 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.
  */
 
 
@@ -289,22 +356,22 @@ my_error_exit(j_common_ptr cinfo)
 
 
 METHODDEF(int) do_read_JPEG_file(struct jpeg_decompress_struct *cinfo,
-                                 char *filename);
+                                 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.
  */
 
-GLOBAL(int)
-read_JPEG_file(char *filename)
+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, filename);
+  return do_read_JPEG_file(&cinfo, infilename, outfilename);
 }
 
 /*
@@ -316,7 +383,8 @@ read_JPEG_file(char *filename)
  */
 
 METHODDEF(int)
-do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
+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
@@ -325,17 +393,28 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
   struct my_error_mgr jerr;
   /* More stuff */
   FILE *infile;                 /* source file */
-  JSAMPARRAY buffer;            /* Output row buffer */
+  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 file before doing anything else,
-   * so that the setjmp() error recovery below can assume the file is open.
+  /* 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 binary files.
+   * requires it in order to read/write binary files.
    */
 
-  if ((infile = fopen(filename, "rb")) == NULL) {
-    fprintf(stderr, "can't open %s\n", filename);
+  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;
   }
 
@@ -351,6 +430,7 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
      */
     jpeg_destroy_decompress(cinfo);
     fclose(infile);
+    fclose(outfile);
     return 0;
   }
   /* Now we can initialize the JPEG decompression object. */
@@ -369,6 +449,10 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
    * See libjpeg.txt for more info.
    */
 
+  /* emit header for raw PPM format */
+  fprintf(outfile, "P6\n%d %d\n%d\n", WIDTH, 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
@@ -388,11 +472,15 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
    * if we asked for color quantization.
    * In this example, we need to make an output work buffer of the right size.
    */
-  /* JSAMPLEs per row in output buffer */
+  /* 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 */
-  buffer = (*cinfo->mem->alloc_sarray)
-                ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
+  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(...); */
@@ -400,14 +488,30 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
   /* 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.
    */
-  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);
-    /* Assume put_scanline_someplace wants a pointer and sample count. */
-    put_scanline_someplace(buffer[0], row_stride);
+  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 */
@@ -422,12 +526,13 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
   /* 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 file.
+  /* 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).
@@ -462,3 +567,88 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *filename)
  * On some systems you may need to set up a signal handler to ensure that
  * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
  */
+
+
+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;
+}
index 9f044c6..a08cb46 100644 (file)
@@ -45,6 +45,14 @@ add_fuzz_target(compress compress.cc)
 
 add_fuzz_target(compress_yuv compress_yuv.cc)
 
+add_fuzz_target(compress_lossless compress_lossless.cc)
+
+add_fuzz_target(compress12 compress12.cc)
+
+add_fuzz_target(compress12_lossless compress12.cc)
+
+add_fuzz_target(compress16_lossless compress16_lossless.cc)
+
 # NOTE: This target is named libjpeg_turbo_fuzzer instead of decompress_fuzzer
 # in order to preserve the corpora from Google's OSS-Fuzz target for
 # libjpeg-turbo, which this target replaces.
index 7033022..d87cbdf 100644 (file)
@@ -20,6 +20,10 @@ make install
 cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/cjpeg_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
 cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
 cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress_yuv_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
+cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress_lossless_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
+cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress12_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
+cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress12_lossless_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
+cp $SRC/compress_fuzzer_seed_corpus.zip $OUT/compress16_lossless_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
 cp $SRC/decompress_fuzzer_seed_corpus.zip $OUT/libjpeg_turbo_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
 cp $SRC/decompress_fuzzer_seed_corpus.zip $OUT/decompress_yuv_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
 cp $SRC/decompress_fuzzer_seed_corpus.zip $OUT/transform_fuzzer${FUZZER_SUFFIX}_seed_corpus.zip
index 539932f..f59f66d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2021, 2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -35,8 +35,6 @@
 
 
 #define NUMTESTS  7
-/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
-#define TJFLAG_FUZZING  (1 << 30)
 
 
 struct test {
@@ -73,37 +71,40 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
     goto bailout;
 
-  if ((handle = tjInitCompress()) == NULL)
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
     goto bailout;
 
   for (ti = 0; ti < NUMTESTS; ti++) {
-    int flags = TJFLAG_FUZZING, sum = 0, pf = tests[ti].pf;
-    unsigned long dstSize = 0, maxBufSize;
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
 
     /* Test non-default compression options on specific iterations. */
-    if (ti == 0)
-      flags |= TJFLAG_BOTTOMUP | TJFLAG_ACCURATEDCT;
-    else if (ti == 1)
-      flags |= TJFLAG_PROGRESSIVE;
-    if (ti != 2)
-      flags |= TJFLAG_NOREALLOC;
-
-    /* tjLoadImage() refuses to load images larger than 1 Megapixel when
-       FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION is defined (yes, that's a dirty
-       hack), so we don't need to check the width and height here. */
-    if ((srcBuf = tjLoadImage(filename, &width, 1, &height, &pf,
-                              flags)) == NULL)
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_FASTDCT, ti == 1);
+    tj3Set(handle, TJPARAM_OPTIMIZE, ti == 6);
+    tj3Set(handle, TJPARAM_PROGRESSIVE, ti == 1 || ti == 3);
+    tj3Set(handle, TJPARAM_ARITHMETIC, ti == 2 || ti == 3);
+    tj3Set(handle, TJPARAM_NOREALLOC, ti != 2);
+    tj3Set(handle, TJPARAM_RESTARTROWS, ti == 1 || ti == 2 ? 2 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height,
+                                &pf)) == NULL)
       continue;
 
-    maxBufSize = tjBufSize(width, height, tests[ti].subsamp);
-    if (flags & TJFLAG_NOREALLOC) {
+    maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp);
+    if (tj3Get(handle, TJPARAM_NOREALLOC)) {
       if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
         goto bailout;
     } else
       dstBuf = NULL;
 
-    if (tjCompress2(handle, srcBuf, width, 0, height, pf, &dstBuf, &dstSize,
-                    tests[ti].subsamp, tests[ti].quality, flags) == 0) {
+    tj3Set(handle, TJPARAM_SUBSAMP, tests[ti].subsamp);
+    tj3Set(handle, TJPARAM_QUALITY, tests[ti].quality);
+    if (tj3Compress8(handle, srcBuf, width, 0, height, pf, &dstBuf,
+                     &dstSize) == 0) {
       /* Touch all of the output pixels in order to catch uninitialized reads
          when using MemorySanitizer. */
       for (i = 0; i < dstSize; i++)
@@ -112,7 +113,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 
     free(dstBuf);
     dstBuf = NULL;
-    tjFree(srcBuf);
+    tj3Free(srcBuf);
     srcBuf = NULL;
 
     /* Prevent the code above from being optimized out.  This test should never
@@ -123,11 +124,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 
 bailout:
   free(dstBuf);
-  tjFree(srcBuf);
+  tj3Free(srcBuf);
   if (fd >= 0) {
     close(fd);
     if (strlen(filename) > 0) unlink(filename);
   }
-  if (handle) tjDestroy(handle);
+  tj3Destroy(handle);
   return 0;
 }
diff --git a/fuzz/compress12.cc b/fuzz/compress12.cc
new file mode 100644 (file)
index 0000000..8a08299
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C)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.
+ */
+
+#include <turbojpeg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#define NUMTESTS  7
+
+
+struct test {
+  enum TJPF pf;
+  enum TJSAMP subsamp;
+  int quality;
+};
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  tjhandle handle = NULL;
+  short *srcBuf = NULL;
+  unsigned char *dstBuf = NULL;
+  int width = 0, height = 0, fd = -1, i, ti;
+  char filename[FILENAME_MAX] = { 0 };
+  struct test tests[NUMTESTS] = {
+    { TJPF_RGB, TJSAMP_444, 100 },
+    { TJPF_BGR, TJSAMP_422, 90 },
+    { TJPF_RGBX, TJSAMP_420, 80 },
+    { TJPF_BGRA, TJSAMP_411, 70 },
+    { TJPF_XRGB, TJSAMP_GRAY, 60 },
+    { TJPF_GRAY, TJSAMP_GRAY, 50 },
+    { TJPF_CMYK, TJSAMP_440, 40 }
+  };
+#if defined(__has_feature) && __has_feature(memory_sanitizer)
+  char env[18] = "JSIMD_FORCENONE=1";
+
+  /* The libjpeg-turbo SIMD extensions produce false positives with
+     MemorySanitizer. */
+  putenv(env);
+#endif
+
+  snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress12_fuzz.XXXXXX");
+  if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
+    goto bailout;
+
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    goto bailout;
+
+  for (ti = 0; ti < NUMTESTS; ti++) {
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
+
+    /* Test non-default compression options on specific iterations. */
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_FASTDCT, ti == 0);
+    tj3Set(handle, TJPARAM_PROGRESSIVE, ti == 1 || ti == 3);
+    tj3Set(handle, TJPARAM_ARITHMETIC, ti == 2 || ti == 3);
+    tj3Set(handle, TJPARAM_NOREALLOC, ti != 2);
+    tj3Set(handle, TJPARAM_RESTARTROWS, ti == 1 || ti == 2 ? 2 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage12() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage12(handle, filename, &width, 1, &height,
+                                 &pf)) == NULL)
+      continue;
+
+    maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp);
+    if (tj3Get(handle, TJPARAM_NOREALLOC)) {
+      if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
+        goto bailout;
+    } else
+      dstBuf = NULL;
+
+    tj3Set(handle, TJPARAM_SUBSAMP, tests[ti].subsamp);
+    tj3Set(handle, TJPARAM_QUALITY, tests[ti].quality);
+    if (tj3Compress12(handle, srcBuf, width, 0, height, pf, &dstBuf,
+                      &dstSize) == 0) {
+      /* Touch all of the output pixels in order to catch uninitialized reads
+         when using MemorySanitizer. */
+      for (i = 0; i < dstSize; i++)
+        sum += dstBuf[i];
+    }
+
+    free(dstBuf);
+    dstBuf = NULL;
+    tj3Free(srcBuf);
+    srcBuf = NULL;
+
+    /* Prevent the code above from being optimized out.  This test should never
+       be true, but the compiler doesn't know that. */
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+bailout:
+  free(dstBuf);
+  tj3Free(srcBuf);
+  if (fd >= 0) {
+    close(fd);
+    if (strlen(filename) > 0) unlink(filename);
+  }
+  tj3Destroy(handle);
+  return 0;
+}
diff --git a/fuzz/compress12_lossless.cc b/fuzz/compress12_lossless.cc
new file mode 100644 (file)
index 0000000..76a0a0d
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C)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.
+ */
+
+#include <turbojpeg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#define NUMTESTS  7
+
+
+struct test {
+  enum TJPF pf;
+  int psv, pt;
+};
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  tjhandle handle = NULL;
+  short *srcBuf = NULL;
+  unsigned char *dstBuf = NULL;
+  int width = 0, height = 0, fd = -1, i, ti;
+  char filename[FILENAME_MAX] = { 0 };
+  struct test tests[NUMTESTS] = {
+    { TJPF_RGB, 1, 0 },
+    { TJPF_BGR, 2, 2 },
+    { TJPF_RGBX, 3, 4 },
+    { TJPF_BGRA, 4, 7 },
+    { TJPF_XRGB, 5, 5 },
+    { TJPF_GRAY, 6, 3 },
+    { TJPF_CMYK, 7, 0 }
+  };
+#if defined(__has_feature) && __has_feature(memory_sanitizer)
+  char env[18] = "JSIMD_FORCENONE=1";
+
+  /* The libjpeg-turbo SIMD extensions produce false positives with
+     MemorySanitizer. */
+  putenv(env);
+#endif
+
+  snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX");
+  if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
+    goto bailout;
+
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    goto bailout;
+
+  for (ti = 0; ti < NUMTESTS; ti++) {
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
+
+    /* Test non-default compression options on specific iterations. */
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_NOREALLOC, ti != 2);
+    tj3Set(handle, TJPARAM_RESTARTROWS, ti == 0 || ti == 6 ? 1 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage12() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage12(handle, filename, &width, 1, &height,
+                                 &pf)) == NULL)
+      continue;
+
+    maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444);
+    if (tj3Get(handle, TJPARAM_NOREALLOC)) {
+      if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
+        goto bailout;
+    } else
+      dstBuf = NULL;
+
+    tj3Set(handle, TJPARAM_LOSSLESS, 1);
+    tj3Set(handle, TJPARAM_LOSSLESSPSV, tests[ti].psv);
+    tj3Set(handle, TJPARAM_LOSSLESSPT, tests[ti].pt);
+    if (tj3Compress12(handle, srcBuf, width, 0, height, pf, &dstBuf,
+                      &dstSize) == 0) {
+      /* Touch all of the output pixels in order to catch uninitialized reads
+         when using MemorySanitizer. */
+      for (i = 0; i < dstSize; i++)
+        sum += dstBuf[i];
+    }
+
+    free(dstBuf);
+    dstBuf = NULL;
+    tj3Free(srcBuf);
+    srcBuf = NULL;
+
+    /* Prevent the code above from being optimized out.  This test should never
+       be true, but the compiler doesn't know that. */
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+bailout:
+  free(dstBuf);
+  tj3Free(srcBuf);
+  if (fd >= 0) {
+    close(fd);
+    if (strlen(filename) > 0) unlink(filename);
+  }
+  tj3Destroy(handle);
+  return 0;
+}
diff --git a/fuzz/compress16_lossless.cc b/fuzz/compress16_lossless.cc
new file mode 100644 (file)
index 0000000..aa6037e
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C)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.
+ */
+
+#include <turbojpeg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#define NUMTESTS  7
+
+
+struct test {
+  enum TJPF pf;
+  int psv, pt;
+};
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  tjhandle handle = NULL;
+  unsigned short *srcBuf = NULL;
+  unsigned char *dstBuf = NULL;
+  int width = 0, height = 0, fd = -1, i, ti;
+  char filename[FILENAME_MAX] = { 0 };
+  struct test tests[NUMTESTS] = {
+    { TJPF_RGB, 1, 0 },
+    { TJPF_BGR, 2, 2 },
+    { TJPF_RGBX, 3, 4 },
+    { TJPF_BGRA, 4, 7 },
+    { TJPF_XRGB, 5, 5 },
+    { TJPF_GRAY, 6, 3 },
+    { TJPF_CMYK, 7, 0 }
+  };
+#if defined(__has_feature) && __has_feature(memory_sanitizer)
+  char env[18] = "JSIMD_FORCENONE=1";
+
+  /* The libjpeg-turbo SIMD extensions produce false positives with
+     MemorySanitizer. */
+  putenv(env);
+#endif
+
+  snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX");
+  if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
+    goto bailout;
+
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    goto bailout;
+
+  for (ti = 0; ti < NUMTESTS; ti++) {
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
+
+    /* Test non-default compression options on specific iterations. */
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_NOREALLOC, ti != 2);
+    tj3Set(handle, TJPARAM_RESTARTROWS, ti == 0 || ti == 6 ? 1 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage16() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage16(handle, filename, &width, 1, &height,
+                                 &pf)) == NULL)
+      continue;
+
+    maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444);
+    if (tj3Get(handle, TJPARAM_NOREALLOC)) {
+      if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
+        goto bailout;
+    } else
+      dstBuf = NULL;
+
+    tj3Set(handle, TJPARAM_LOSSLESS, 1);
+    tj3Set(handle, TJPARAM_LOSSLESSPSV, tests[ti].psv);
+    tj3Set(handle, TJPARAM_LOSSLESSPT, tests[ti].pt);
+    if (tj3Compress16(handle, srcBuf, width, 0, height, pf, &dstBuf,
+                      &dstSize) == 0) {
+      /* Touch all of the output pixels in order to catch uninitialized reads
+         when using MemorySanitizer. */
+      for (i = 0; i < dstSize; i++)
+        sum += dstBuf[i];
+    }
+
+    free(dstBuf);
+    dstBuf = NULL;
+    tj3Free(srcBuf);
+    srcBuf = NULL;
+
+    /* Prevent the code above from being optimized out.  This test should never
+       be true, but the compiler doesn't know that. */
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+bailout:
+  free(dstBuf);
+  tj3Free(srcBuf);
+  if (fd >= 0) {
+    close(fd);
+    if (strlen(filename) > 0) unlink(filename);
+  }
+  tj3Destroy(handle);
+  return 0;
+}
diff --git a/fuzz/compress_lossless.cc b/fuzz/compress_lossless.cc
new file mode 100644 (file)
index 0000000..7c2bb79
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C)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.
+ */
+
+#include <turbojpeg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#define NUMTESTS  7
+
+
+struct test {
+  enum TJPF pf;
+  int psv, pt;
+};
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+  tjhandle handle = NULL;
+  unsigned char *srcBuf = NULL, *dstBuf = NULL;
+  int width = 0, height = 0, fd = -1, i, ti;
+  char filename[FILENAME_MAX] = { 0 };
+  struct test tests[NUMTESTS] = {
+    { TJPF_RGB, 1, 0 },
+    { TJPF_BGR, 2, 2 },
+    { TJPF_RGBX, 3, 4 },
+    { TJPF_BGRA, 4, 7 },
+    { TJPF_XRGB, 5, 5 },
+    { TJPF_GRAY, 6, 3 },
+    { TJPF_CMYK, 7, 0 }
+  };
+#if defined(__has_feature) && __has_feature(memory_sanitizer)
+  char env[18] = "JSIMD_FORCENONE=1";
+
+  /* The libjpeg-turbo SIMD extensions produce false positives with
+     MemorySanitizer. */
+  putenv(env);
+#endif
+
+  snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_fuzz.XXXXXX");
+  if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
+    goto bailout;
+
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    goto bailout;
+
+  for (ti = 0; ti < NUMTESTS; ti++) {
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
+
+    /* Test non-default compression options on specific iterations. */
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_NOREALLOC, ti != 2);
+    tj3Set(handle, TJPARAM_RESTARTROWS, ti == 0 || ti == 6 ? 1 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height,
+                                &pf)) == NULL)
+      continue;
+
+    maxBufSize = tj3JPEGBufSize(width, height, TJSAMP_444);
+    if (tj3Get(handle, TJPARAM_NOREALLOC)) {
+      if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
+        goto bailout;
+    } else
+      dstBuf = NULL;
+
+    tj3Set(handle, TJPARAM_LOSSLESS, 1);
+    tj3Set(handle, TJPARAM_LOSSLESSPSV, tests[ti].psv);
+    tj3Set(handle, TJPARAM_LOSSLESSPT, tests[ti].pt);
+    if (tj3Compress8(handle, srcBuf, width, 0, height, pf, &dstBuf,
+                     &dstSize) == 0) {
+      /* Touch all of the output pixels in order to catch uninitialized reads
+         when using MemorySanitizer. */
+      for (i = 0; i < dstSize; i++)
+        sum += dstBuf[i];
+    }
+
+    free(dstBuf);
+    dstBuf = NULL;
+    tj3Free(srcBuf);
+    srcBuf = NULL;
+
+    /* Prevent the code above from being optimized out.  This test should never
+       be true, but the compiler doesn't know that. */
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+bailout:
+  free(dstBuf);
+  tj3Free(srcBuf);
+  if (fd >= 0) {
+    close(fd);
+    if (strlen(filename) > 0) unlink(filename);
+  }
+  tj3Destroy(handle);
+  return 0;
+}
index 021d661..0b12e0c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2021-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -35,8 +35,6 @@
 
 
 #define NUMTESTS  6
-/* Private flag that triggers different TurboJPEG API behavior when fuzzing */
-#define TJFLAG_FUZZING  (1 << 30)
 
 
 struct test {
@@ -60,62 +58,54 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
     { TJPF_BGR, TJSAMP_GRAY, 60 },
     { TJPF_GRAY, TJSAMP_GRAY, 50 }
   };
-  char arithEnv[16] = "TJ_ARITHMETIC=0";
-  char restartEnv[13] = "TJ_RESTART=0";
 #if defined(__has_feature) && __has_feature(memory_sanitizer)
-  char simdEnv[18] = "JSIMD_FORCENONE=1";
+  char env[18] = "JSIMD_FORCENONE=1";
 
   /* The libjpeg-turbo SIMD extensions produce false positives with
      MemorySanitizer. */
-  putenv(simdEnv);
+  putenv(env);
 #endif
-  putenv(arithEnv);
-  putenv(restartEnv);
 
   snprintf(filename, FILENAME_MAX, "/tmp/libjpeg-turbo_compress_yuv_fuzz.XXXXXX");
   if ((fd = mkstemp(filename)) < 0 || write(fd, data, size) < 0)
     goto bailout;
 
-  if ((handle = tjInitCompress()) == NULL)
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
     goto bailout;
 
   for (ti = 0; ti < NUMTESTS; ti++) {
-    int flags = TJFLAG_FUZZING | TJFLAG_NOREALLOC, sum = 0, pf = tests[ti].pf;
-    unsigned long dstSize = 0, maxBufSize;
+    int sum = 0, pf = tests[ti].pf;
+    size_t dstSize = 0, maxBufSize;
 
     /* Test non-default compression options on specific iterations. */
-    if (ti == 0)
-      flags |= TJFLAG_BOTTOMUP | TJFLAG_ACCURATEDCT;
-    else if (ti == 1 || ti == 3)
-      flags |= TJFLAG_PROGRESSIVE;
-    if (ti == 2 || ti == 3)
-      arithEnv[14] = '1';
-    else
-      arithEnv[14] = '0';
-    if (ti == 1 || ti == 2)
-      restartEnv[11] = '2';
-    else
-      restartEnv[11] = '0';
-
-    /* tjLoadImage() refuses to load images larger than 1 Megapixel when
-       FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION is defined (yes, that's a dirty
-       hack), so we don't need to check the width and height here. */
-    if ((srcBuf = tjLoadImage(filename, &width, 1, &height, &pf,
-                              flags)) == NULL)
+    tj3Set(handle, TJPARAM_BOTTOMUP, ti == 0);
+    tj3Set(handle, TJPARAM_FASTDCT, ti == 1);
+    tj3Set(handle, TJPARAM_OPTIMIZE, ti == 4);
+    tj3Set(handle, TJPARAM_PROGRESSIVE, ti == 1 || ti == 3);
+    tj3Set(handle, TJPARAM_ARITHMETIC, ti == 2 || ti == 3);
+    tj3Set(handle, TJPARAM_NOREALLOC, 1);
+    tj3Set(handle, TJPARAM_RESTARTBLOCKS, ti == 3 || ti == 4 ? 4 : 0);
+
+    tj3Set(handle, TJPARAM_MAXPIXELS, 1048576);
+    /* tj3LoadImage8() will refuse to load images larger than 1 Megapixel, so
+       we don't need to check the width and height here. */
+    if ((srcBuf = tj3LoadImage8(handle, filename, &width, 1, &height,
+                                &pf)) == NULL)
       continue;
 
-    maxBufSize = tjBufSize(width, height, tests[ti].subsamp);
+    maxBufSize = tj3JPEGBufSize(width, height, tests[ti].subsamp);
     if ((dstBuf = (unsigned char *)malloc(maxBufSize)) == NULL)
       goto bailout;
     if ((yuvBuf =
-         (unsigned char *)malloc(tjBufSizeYUV2(width, 1, height,
+         (unsigned char *)malloc(tj3YUVBufSize(width, 1, height,
                                                tests[ti].subsamp))) == NULL)
       goto bailout;
 
-    if (tjEncodeYUV3(handle, srcBuf, width, 0, height, pf, yuvBuf, 1,
-                     tests[ti].subsamp, flags) == 0 &&
-        tjCompressFromYUV(handle, yuvBuf, width, 1, height, tests[ti].subsamp,
-                          &dstBuf, &dstSize, tests[ti].quality, flags) == 0) {
+    tj3Set(handle, TJPARAM_SUBSAMP, tests[ti].subsamp);
+    tj3Set(handle, TJPARAM_QUALITY, tests[ti].quality);
+    if (tj3EncodeYUV8(handle, srcBuf, width, 0, height, pf, yuvBuf, 1) == 0 &&
+        tj3CompressFromYUV8(handle, yuvBuf, width, 1, height, &dstBuf,
+                            &dstSize) == 0) {
       /* Touch all of the output pixels in order to catch uninitialized reads
          when using MemorySanitizer. */
       for (i = 0; i < dstSize; i++)
@@ -126,7 +116,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
     dstBuf = NULL;
     free(yuvBuf);
     yuvBuf = NULL;
-    tjFree(srcBuf);
+    tj3Free(srcBuf);
     srcBuf = NULL;
 
     /* Prevent the code above from being optimized out.  This test should never
@@ -138,11 +128,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 bailout:
   free(dstBuf);
   free(yuvBuf);
-  tjFree(srcBuf);
+  tj3Free(srcBuf);
   if (fd >= 0) {
     close(fd);
     if (strlen(filename) > 0) unlink(filename);
   }
-  if (handle) tjDestroy(handle);
+  tj3Destroy(handle);
   return 0;
 }
index c7fcb50..eadc734 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2021-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -37,8 +37,8 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   tjhandle handle = NULL;
-  unsigned char *dstBuf = NULL;
-  int width = 0, height = 0, jpegSubsamp, jpegColorspace, pfi;
+  void *dstBuf = NULL;
+  int width = 0, height = 0, precision, sampleSize, pfi;
   /* TJPF_RGB-TJPF_BGR share the same code paths, as do TJPF_RGBX-TJPF_XRGB and
      TJPF_RGBA-TJPF_ARGB.  Thus, the pixel formats below should be the minimum
      necessary to achieve full coverage. */
@@ -52,14 +52,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   putenv(env);
 #endif
 
-  if ((handle = tjInitDecompress()) == NULL)
+  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL)
     goto bailout;
 
-  /* We ignore the return value of tjDecompressHeader3(), because some JPEG
-     images may have unusual subsampling configurations that the TurboJPEG API
-     cannot identify but can still decompress. */
-  tjDecompressHeader3(handle, data, size, &width, &height, &jpegSubsamp,
-                      &jpegColorspace);
+  /* We ignore the return value of tj3DecompressHeader(), because malformed
+     JPEG images that might expose issues in libjpeg-turbo might also have
+     header errors that cause tj3DecompressHeader() to fail. */
+  tj3DecompressHeader(handle, data, size);
+  width = tj3Get(handle, TJPARAM_JPEGWIDTH);
+  height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+  precision = tj3Get(handle, TJPARAM_PRECISION);
+  sampleSize = (precision > 8 ? 2 : 1);
 
   /* Ignore 0-pixel images and images larger than 1 Megapixel, as Google's
      OSS-Fuzz target for libjpeg-turbo did.  Casting width to (uint64_t)
@@ -67,27 +70,67 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   if (width < 1 || height < 1 || (uint64_t)width * height > 1048576)
     goto bailout;
 
+  tj3Set(handle, TJPARAM_SCANLIMIT, 500);
+
   for (pfi = 0; pfi < NUMPF; pfi++) {
-    int pf = pixelFormats[pfi], flags = TJFLAG_LIMITSCANS, i, sum = 0;
     int w = width, h = height;
+    int pf = pixelFormats[pfi], i;
+    int64_t sum = 0;
 
     /* Test non-default decompression options on the first iteration. */
-    if (pfi == 0)
-      flags |= TJFLAG_BOTTOMUP | TJFLAG_FASTUPSAMPLE | TJFLAG_FASTDCT;
-    /* Test IDCT scaling on the second iteration. */
-    else if (pfi == 1) {
-      w = (width + 1) / 2;
-      h = (height + 1) / 2;
+    tj3Set(handle, TJPARAM_BOTTOMUP, pfi == 0);
+    tj3Set(handle, TJPARAM_FASTUPSAMPLE, pfi == 0);
+
+    if (!tj3Get(handle, TJPARAM_LOSSLESS)) {
+      tj3Set(handle, TJPARAM_FASTDCT, pfi == 0);
+
+      /* Test IDCT scaling on the second iteration. */
+      if (pfi == 1) {
+        tjscalingfactor sf = { 1, 2 };
+        tj3SetScalingFactor(handle, sf);
+        w = TJSCALED(width, sf);
+        h = TJSCALED(height, sf);
+      } else
+        tj3SetScalingFactor(handle, TJUNSCALED);
+
+      /* Test partial image decompression on the fourth iteration, if the image
+         is large enough. */
+      if (pfi == 3 && w >= 97 && h >= 75) {
+        tjregion cr = { 32, 16, 65, 59 };
+        tj3SetCroppingRegion(handle, cr);
+      } else
+        tj3SetCroppingRegion(handle, TJUNCROPPED);
     }
 
-    if ((dstBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
+    if ((dstBuf = malloc(w * h * tjPixelSize[pf] * sampleSize)) == NULL)
       goto bailout;
 
-    if (tjDecompress2(handle, data, size, dstBuf, w, 0, h, pf, flags) == 0) {
-      /* Touch all of the output pixels in order to catch uninitialized reads
-         when using MemorySanitizer. */
-      for (i = 0; i < w * h * tjPixelSize[pf]; i++)
-        sum += dstBuf[i];
+    if (precision == 8) {
+      if (tj3Decompress8(handle, data, size, (unsigned char *)dstBuf, 0,
+                         pf) == 0) {
+        /* Touch all of the output pixels in order to catch uninitialized reads
+           when using MemorySanitizer. */
+        for (i = 0; i < w * h * tjPixelSize[pf]; i++)
+          sum += ((unsigned char *)dstBuf)[i];
+      } else
+        goto bailout;
+    } else if (precision == 12) {
+      if (tj3Decompress12(handle, data, size, (short *)dstBuf, 0, pf) == 0) {
+        /* Touch all of the output pixels in order to catch uninitialized reads
+           when using MemorySanitizer. */
+        for (i = 0; i < w * h * tjPixelSize[pf]; i++)
+          sum += ((short *)dstBuf)[i];
+      } else
+        goto bailout;
+    } else {
+      if (tj3Decompress16(handle, data, size, (unsigned short *)dstBuf, 0,
+                          pf) == 0) {
+        /* Touch all of the output pixels in order to catch uninitialized reads
+           when using MemorySanitizer. */
+        for (i = 0; i < w * h * tjPixelSize[pf]; i++)
+          sum += ((unsigned short *)dstBuf)[i];
+      } else
+        goto bailout;
     }
 
     free(dstBuf);
@@ -95,12 +138,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 
     /* Prevent the code above from being optimized out.  This test should never
        be true, but the compiler doesn't know that. */
-    if (sum > 255 * 1048576 * tjPixelSize[pf])
+    if (sum > ((1LL << precision) - 1LL) * 1048576LL * tjPixelSize[pf])
       goto bailout;
   }
 
 bailout:
   free(dstBuf);
-  if (handle) tjDestroy(handle);
+  tj3Destroy(handle);
   return 0;
 }
index d603fd8..4e869df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2021-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -38,7 +38,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   tjhandle handle = NULL;
   unsigned char *dstBuf = NULL, *yuvBuf = NULL;
-  int width = 0, height = 0, jpegSubsamp, jpegColorspace, pfi;
+  int width = 0, height = 0, jpegSubsamp, pfi;
   /* TJPF_RGB-TJPF_BGR share the same code paths, as do TJPF_RGBX-TJPF_XRGB and
      TJPF_RGBA-TJPF_ARGB.  Thus, the pixel formats below should be the minimum
      necessary to achieve full coverage. */
@@ -52,45 +52,58 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   putenv(env);
 #endif
 
-  if ((handle = tjInitDecompress()) == NULL)
+  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL)
     goto bailout;
 
-  if (tjDecompressHeader3(handle, data, size, &width, &height, &jpegSubsamp,
-                          &jpegColorspace) < 0)
-    goto bailout;
+  /* We ignore the return value of tj3DecompressHeader(), because malformed
+     JPEG images that might expose issues in libjpeg-turbo might also have
+     header errors that cause tj3DecompressHeader() to fail. */
+  tj3DecompressHeader(handle, data, size);
+  width = tj3Get(handle, TJPARAM_JPEGWIDTH);
+  height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+  jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
 
   /* Ignore 0-pixel images and images larger than 1 Megapixel.  Casting width
      to (uint64_t) prevents integer overflow if width * height > INT_MAX. */
   if (width < 1 || height < 1 || (uint64_t)width * height > 1048576)
     goto bailout;
 
+  tj3Set(handle, TJPARAM_SCANLIMIT, 500);
+
   for (pfi = 0; pfi < NUMPF; pfi++) {
-    int pf = pixelFormats[pfi], flags = TJFLAG_LIMITSCANS, i, sum = 0;
     int w = width, h = height;
+    int pf = pixelFormats[pfi], i, sum = 0;
 
     /* Test non-default decompression options on the first iteration. */
-    if (pfi == 0)
-      flags |= TJFLAG_BOTTOMUP | TJFLAG_FASTUPSAMPLE | TJFLAG_FASTDCT;
-    /* Test IDCT scaling on the second iteration. */
-    else if (pfi == 1) {
-      w = (width + 3) / 4;
-      h = (height + 3) / 4;
+    if (!tj3Get(handle, TJPARAM_LOSSLESS)) {
+      tj3Set(handle, TJPARAM_BOTTOMUP, pfi == 0);
+      tj3Set(handle, TJPARAM_FASTUPSAMPLE, pfi == 0);
+      tj3Set(handle, TJPARAM_FASTDCT, pfi == 0);
+
+      /* Test IDCT scaling on the second iteration. */
+      if (pfi == 1) {
+        tjscalingfactor sf = { 3, 4 };
+        tj3SetScalingFactor(handle, sf);
+        w = TJSCALED(width, sf);
+        h = TJSCALED(height, sf);
+      } else
+        tj3SetScalingFactor(handle, TJUNSCALED);
     }
 
     if ((dstBuf = (unsigned char *)malloc(w * h * tjPixelSize[pf])) == NULL)
       goto bailout;
     if ((yuvBuf =
-         (unsigned char *)malloc(tjBufSizeYUV2(w, 1, h, jpegSubsamp))) == NULL)
+         (unsigned char *)malloc(tj3YUVBufSize(w, 1, h, jpegSubsamp))) == NULL)
       goto bailout;
 
-    if (tjDecompressToYUV2(handle, data, size, yuvBuf, w, 1, h, flags) == 0 &&
-        tjDecodeYUV(handle, yuvBuf, 1, jpegSubsamp, dstBuf, w, 0, h, pf,
-                    flags) == 0) {
+    if (tj3DecompressToYUV8(handle, data, size, yuvBuf, 1) == 0 &&
+        tj3DecodeYUV8(handle, yuvBuf, 1, dstBuf, w, 0, h, pf) == 0) {
       /* Touch all of the output pixels in order to catch uninitialized reads
          when using MemorySanitizer. */
       for (i = 0; i < w * h * tjPixelSize[pf]; i++)
         sum += dstBuf[i];
-    }
+    } else
+      goto bailout;
 
     free(dstBuf);
     dstBuf = NULL;
@@ -106,6 +119,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 bailout:
   free(dstBuf);
   free(yuvBuf);
-  if (handle) tjDestroy(handle);
+  tj3Destroy(handle);
   return 0;
 }
index b8a7516..8d2e6ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2021 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2021-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
 #include <string.h>
 
 
-#define NUMXFORMS  3
-
-
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
   tjhandle handle = NULL;
-  unsigned char *dstBufs[NUMXFORMS] = { NULL, NULL, NULL };
-  unsigned long dstSizes[NUMXFORMS] = { 0, 0, 0 }, maxBufSize;
-  int width = 0, height = 0, jpegSubsamp, jpegColorspace, i, t;
-  tjtransform transforms[NUMXFORMS];
+  unsigned char *dstBufs[1] = { NULL };
+  size_t dstSizes[1] = { 0 }, maxBufSize;
+  int width = 0, height = 0, jpegSubsamp, i;
+  tjtransform transforms[1];
 #if defined(__has_feature) && __has_feature(memory_sanitizer)
   char env[18] = "JSIMD_FORCENONE=1";
 
@@ -50,74 +47,118 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   putenv(env);
 #endif
 
-  if ((handle = tjInitTransform()) == NULL)
+  if ((handle = tj3Init(TJINIT_TRANSFORM)) == NULL)
     goto bailout;
 
-  /* We ignore the return value of tjDecompressHeader3(), because some JPEG
-     images may have unusual subsampling configurations that the TurboJPEG API
-     cannot identify but can still transform. */
-  tjDecompressHeader3(handle, data, size, &width, &height, &jpegSubsamp,
-                      &jpegColorspace);
+  /* We ignore the return value of tj3DecompressHeader(), because malformed
+     JPEG images that might expose issues in libjpeg-turbo might also have
+     header errors that cause tj3DecompressHeader() to fail. */
+  tj3DecompressHeader(handle, data, size);
+  width = tj3Get(handle, TJPARAM_JPEGWIDTH);
+  height = tj3Get(handle, TJPARAM_JPEGHEIGHT);
+  jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+  /* Let the transform options dictate the entropy coding algorithm. */
+  tj3Set(handle, TJPARAM_ARITHMETIC, 0);
+  tj3Set(handle, TJPARAM_PROGRESSIVE, 0);
+  tj3Set(handle, TJPARAM_OPTIMIZE, 0);
 
   /* Ignore 0-pixel images and images larger than 1 Megapixel.  Casting width
      to (uint64_t) prevents integer overflow if width * height > INT_MAX. */
   if (width < 1 || height < 1 || (uint64_t)width * height > 1048576)
     goto bailout;
 
+  tj3Set(handle, TJPARAM_SCANLIMIT, 500);
+
   if (jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
     jpegSubsamp = TJSAMP_444;
 
-  for (t = 0; t < NUMXFORMS; t++)
-    memset(&transforms[t], 0, sizeof(tjtransform));
+  memset(&transforms[0], 0, sizeof(tjtransform));
 
   transforms[0].op = TJXOP_NONE;
   transforms[0].options = TJXOPT_PROGRESSIVE | TJXOPT_COPYNONE;
-  dstBufs[0] = (unsigned char *)malloc(tjBufSize(width, height, jpegSubsamp));
+  dstBufs[0] =
+    (unsigned char *)malloc(tj3JPEGBufSize(width, height, jpegSubsamp));
   if (!dstBufs[0])
     goto bailout;
 
-  transforms[1].r.w = (width + 1) / 2;
-  transforms[1].r.h = (height + 1) / 2;
-  transforms[1].op = TJXOP_TRANSPOSE;
-  transforms[1].options = TJXOPT_GRAY | TJXOPT_CROP | TJXOPT_COPYNONE;
-  dstBufs[1] =
-    (unsigned char *)malloc(tjBufSize((width + 1) / 2, (height + 1) / 2,
-                                      TJSAMP_GRAY));
-  if (!dstBufs[1])
+  maxBufSize = tj3JPEGBufSize(width, height, jpegSubsamp);
+
+  tj3Set(handle, TJPARAM_NOREALLOC, 1);
+  if (tj3Transform(handle, data, size, 1, dstBufs, dstSizes,
+                   transforms) == 0) {
+    /* Touch all of the output pixels in order to catch uninitialized reads
+       when using MemorySanitizer. */
+    int sum = 0;
+
+    for (i = 0; i < dstSizes[0]; i++)
+      sum += dstBufs[0][i];
+
+    /* Prevent the code above from being optimized out.  This test should
+       never be true, but the compiler doesn't know that. */
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+  free(dstBufs[0]);
+  dstBufs[0] = NULL;
+
+  transforms[0].r.w = (height + 1) / 2;
+  transforms[0].r.h = (width + 1) / 2;
+  transforms[0].op = TJXOP_TRANSPOSE;
+  transforms[0].options = TJXOPT_GRAY | TJXOPT_CROP | TJXOPT_COPYNONE |
+                          TJXOPT_OPTIMIZE;
+  dstBufs[0] =
+    (unsigned char *)malloc(tj3JPEGBufSize((height + 1) / 2, (width + 1) / 2,
+                                           jpegSubsamp));
+  if (!dstBufs[0])
     goto bailout;
 
-  transforms[2].op = TJXOP_ROT90;
-  transforms[2].options = TJXOPT_TRIM | TJXOPT_COPYNONE;
-  dstBufs[2] = (unsigned char *)malloc(tjBufSize(height, width, jpegSubsamp));
-  if (!dstBufs[2])
+  maxBufSize = tj3JPEGBufSize((height + 1) / 2, (width + 1) / 2, jpegSubsamp);
+
+  if (tj3Transform(handle, data, size, 1, dstBufs, dstSizes,
+                   transforms) == 0) {
+    int sum = 0;
+
+    for (i = 0; i < dstSizes[0]; i++)
+      sum += dstBufs[0][i];
+
+    if (sum > 255 * maxBufSize)
+      goto bailout;
+  }
+
+  free(dstBufs[0]);
+  dstBufs[0] = NULL;
+
+  transforms[0].op = TJXOP_ROT90;
+  transforms[0].options = TJXOPT_TRIM | TJXOPT_ARITHMETIC;
+  dstBufs[0] =
+    (unsigned char *)malloc(tj3JPEGBufSize(height, width, jpegSubsamp));
+  if (!dstBufs[0])
     goto bailout;
 
-  maxBufSize = tjBufSize(width, height, jpegSubsamp);
+  maxBufSize = tj3JPEGBufSize(height, width, jpegSubsamp);
 
-  if (tjTransform(handle, data, size, NUMXFORMS, dstBufs, dstSizes, transforms,
-                  TJFLAG_LIMITSCANS | TJFLAG_NOREALLOC) == 0) {
-    /* Touch all of the output pixels in order to catch uninitialized reads
-       when using MemorySanitizer. */
-    for (t = 0; t < NUMXFORMS; t++) {
-      int sum = 0;
+  if (tj3Transform(handle, data, size, 1, dstBufs, dstSizes,
+                   transforms) == 0) {
+    int sum = 0;
 
-      for (i = 0; i < dstSizes[t]; i++)
-        sum += dstBufs[t][i];
+    for (i = 0; i < dstSizes[0]; i++)
+      sum += dstBufs[0][i];
 
-      /* Prevent the code above from being optimized out.  This test should
-         never be true, but the compiler doesn't know that. */
-      if (sum > 255 * maxBufSize)
-        goto bailout;
-    }
+    if (sum > 255 * maxBufSize)
+      goto bailout;
   }
 
-  transforms[0].options &= ~TJXOPT_COPYNONE;
   free(dstBufs[0]);
   dstBufs[0] = NULL;
+
+  transforms[0].op = TJXOP_NONE;
+  transforms[0].options = TJXOPT_PROGRESSIVE;
   dstSizes[0] = 0;
 
-  if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms,
-                  TJFLAG_LIMITSCANS) == 0) {
+  tj3Set(handle, TJPARAM_NOREALLOC, 0);
+  if (tj3Transform(handle, data, size, 1, dstBufs, dstSizes,
+                   transforms) == 0) {
     int sum = 0;
 
     for (i = 0; i < dstSizes[0]; i++)
@@ -128,8 +169,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
   }
 
 bailout:
-  for (t = 0; t < NUMXFORMS; t++)
-    free(dstBufs[t]);
-  if (handle) tjDestroy(handle);
+  free(dstBufs[0]);
+  tj3Destroy(handle);
   return 0;
 }
index 3a061d8..e653add 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C)2009-2014, 2016-2019, 2021 D. R. Commander.
- *                                         All Rights Reserved.
+ * Copyright (C)2009-2014, 2016-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:
  */
 
 import java.io.*;
+import java.awt.*;
 import java.awt.image.*;
 import javax.imageio.*;
+import java.nio.*;
 import java.util.*;
 import org.libjpegturbo.turbojpeg.*;
 
@@ -37,30 +39,68 @@ final class TJBench {
 
   private TJBench() {}
 
-  private static int flags = 0, quiet = 0, pf = TJ.PF_BGR, yuvPad = 1;
-  private static boolean compOnly, decompOnly, doTile, doYUV, write = true;
+  private static boolean stopOnWarning, bottomUp, fastUpsample, fastDCT,
+    optimize, progressive, limitScans, arithmetic, lossless;
+  private static int precision = 8, quiet = 0, pf = TJ.PF_BGR, yuvAlign = 1,
+    restartIntervalBlocks, restartIntervalRows = 0;
+  private static boolean compOnly, decompOnly, doTile, doYUV, write = true,
+    bmp = false;
 
   static final String[] PIXFORMATSTR = {
-    "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY"
+    "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "",
+    "CMYK"
   };
 
   static final String[] SUBNAME_LONG = {
-    "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
+    "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
   };
 
   static final String[] SUBNAME = {
-    "444", "422", "420", "GRAY", "440", "411"
+    "444", "422", "420", "GRAY", "440", "411", "441"
   };
 
   static final String[] CSNAME = {
     "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
   };
 
-  private static TJScalingFactor sf;
+  private static TJScalingFactor sf = TJ.UNSCALED;
+  private static java.awt.Rectangle cr = TJ.UNCROPPED;
   private static int xformOp = TJTransform.OP_NONE, xformOpt = 0;
   private static double benchTime = 5.0, warmup = 1.0;
 
 
+  private static class DummyDCTFilter implements TJCustomFilter {
+    public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
+                             Rectangle planeRegion, int componentID,
+                             int transformID, TJTransform transform) {
+      for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++)
+        coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
+    }
+  }
+
+  private static DummyDCTFilter customFilter;
+
+
+  @SuppressWarnings("checkstyle:HiddenField")
+  private static boolean isCropped(java.awt.Rectangle cr) {
+    return (cr.x != 0 || cr.y != 0 || cr.width != 0 || cr.height != 0);
+  }
+
+  private static int getCroppedWidth(int width) {
+    if (isCropped(cr))
+      return (cr.width != 0 ? cr.width : sf.getScaled(width) - cr.x);
+    else
+      return sf.getScaled(width);
+  }
+
+  private static int getCroppedHeight(int height) {
+    if (isCropped(cr))
+      return (cr.height != 0 ? cr.height : sf.getScaled(height) - cr.y);
+    else
+      return sf.getScaled(height);
+  }
+
+
   static double getTime() {
     return (double)System.nanoTime() / 1.0e9;
   }
@@ -73,8 +113,7 @@ final class TJBench {
     String errorMsg = e.getMessage();
     int errorCode = e.getErrorCode();
 
-    if ((flags & TJ.FLAG_STOPONWARNING) == 0 &&
-        errorCode == TJ.ERR_WARNING) {
+    if (!stopOnWarning && errorCode == TJ.ERR_WARNING) {
       if (tjErrorMsg == null || !tjErrorMsg.equals(errorMsg) ||
           tjErrorCode != errorCode) {
         tjErrorMsg = errorMsg;
@@ -87,12 +126,22 @@ final class TJBench {
 
 
   static String formatName(int subsamp, int cs) {
-    if (cs == TJ.CS_YCbCr)
-      return SUBNAME_LONG[subsamp];
-    else if (cs == TJ.CS_YCCK)
-      return CSNAME[cs] + " " + SUBNAME_LONG[subsamp];
-    else
-      return CSNAME[cs];
+    if (quiet != 0) {
+      if (lossless)
+        return String.format("%-2d/LOSSLESS   ", precision);
+      else if (subsamp == TJ.SAMP_UNKNOWN)
+        return String.format("%-2d/%-5s      ", precision, CSNAME[cs]);
+      else
+        return String.format("%-2d/%-5s/%-5s", precision, CSNAME[cs],
+                             SUBNAME_LONG[subsamp]);
+    } else {
+      if (lossless)
+        return "Lossless";
+      else if (subsamp == TJ.SAMP_UNKNOWN)
+        return CSNAME[cs];
+      else
+        return CSNAME[cs] + " " + SUBNAME_LONG[subsamp];
+    }
   }
 
 
@@ -108,91 +157,69 @@ final class TJBench {
   }
 
 
-  static byte[] loadImage(String fileName, int[] w, int[] h, int pixelFormat)
-                          throws Exception {
-    BufferedImage img = ImageIO.read(new File(fileName));
-
-    if (img == null)
-      throw new Exception("Could not read " + fileName);
-    w[0] = img.getWidth();
-    h[0] = img.getHeight();
-
-    int[] rgb = img.getRGB(0, 0, w[0], h[0], null, 0, w[0]);
-    int ps = TJ.getPixelSize(pixelFormat);
-    int rindex = TJ.getRedOffset(pixelFormat);
-    int gindex = TJ.getGreenOffset(pixelFormat);
-    int bindex = TJ.getBlueOffset(pixelFormat);
-    if ((long)w[0] * (long)h[0] * (long)ps > (long)Integer.MAX_VALUE)
-      throw new Exception("Image is too large");
-    byte[] dstBuf = new byte[w[0] * h[0] * ps];
-    int pixels = w[0] * h[0], dstPtr = 0, rgbPtr = 0;
-
-    while (pixels-- > 0) {
-      dstBuf[dstPtr + rindex] = (byte)((rgb[rgbPtr] >> 16) & 0xff);
-      dstBuf[dstPtr + gindex] = (byte)((rgb[rgbPtr] >> 8) & 0xff);
-      dstBuf[dstPtr + bindex] = (byte)(rgb[rgbPtr] & 0xff);
-      dstPtr += ps;
-      rgbPtr++;
-    }
-    return dstBuf;
-  }
-
-
-  static void saveImage(String fileName, byte[] srcBuf, int w, int h,
-                        int pixelFormat) throws Exception {
-    BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
-    int pixels = w * h, srcPtr = 0;
-    int ps = TJ.getPixelSize(pixelFormat);
-    int rindex = TJ.getRedOffset(pixelFormat);
-    int gindex = TJ.getGreenOffset(pixelFormat);
-    int bindex = TJ.getBlueOffset(pixelFormat);
-
-    for (int y = 0; y < h; y++) {
-      for (int x = 0; x < w; x++, srcPtr += ps) {
-        int pixel = (srcBuf[srcPtr + rindex] & 0xff) << 16 |
-                    (srcBuf[srcPtr + gindex] & 0xff) << 8 |
-                    (srcBuf[srcPtr + bindex] & 0xff);
-
-        img.setRGB(x, y, pixel);
-      }
-    }
-    ImageIO.write(img, "bmp", new File(fileName));
-  }
-
-
   /* Decompression test */
-  static void decomp(byte[] srcBuf, byte[][] jpegBuf, int[] jpegSize,
-                     byte[] dstBuf, int w, int h, int subsamp, int jpegQual,
-                     String fileName, int tilew, int tileh) throws Exception {
+  static void decomp(byte[][] jpegBufs, int[] jpegSizes, Object dstBuf, int w,
+                     int h, int subsamp, int jpegQual, String fileName,
+                     int tilew, int tileh) throws Exception {
     String qualStr = new String(""), sizeStr, tempStr;
     TJDecompressor tjd;
     double elapsed, elapsedDecode;
     int ps = TJ.getPixelSize(pf), i, iter = 0;
-    int scaledw = sf.getScaled(w);
-    int scaledh = sf.getScaled(h);
-    int pitch = scaledw * ps;
+    int scaledw, scaledh, pitch;
     YUVImage yuvImage = null;
 
+    if (lossless)
+      sf = TJ.UNSCALED;
+
+    scaledw = sf.getScaled(w);
+    scaledh = sf.getScaled(h);
+
     if (jpegQual > 0)
-      qualStr = new String("_Q" + jpegQual);
+      qualStr = new String((lossless ? "_PSV" : "_Q") + jpegQual);
 
     tjd = new TJDecompressor();
+    tjd.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
+    tjd.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
+    tjd.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0);
+    tjd.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
+    tjd.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0);
+
+    if (isCropped(cr)) {
+      try {
+        tjd.setSourceImage(jpegBufs[0], jpegSizes[0]);
+      } catch (TJException e) { handleTJException(e); }
+    }
+    tjd.setScalingFactor(sf);
+    tjd.setCroppingRegion(cr);
+    if (isCropped(cr)) {
+      scaledw = cr.width != 0 ? cr.width : scaledw - cr.x;
+      scaledh = cr.height != 0 ? cr.height : scaledh - cr.y;
+    }
+    pitch = scaledw * ps;
 
     if (dstBuf == null) {
       if ((long)pitch * (long)scaledh > (long)Integer.MAX_VALUE)
         throw new Exception("Image is too large");
-      dstBuf = new byte[pitch * scaledh];
+      if (precision == 8)
+        dstBuf = new byte[pitch * scaledh];
+      else
+        dstBuf = new short[pitch * scaledh];
     }
 
     /* Set the destination buffer to gray so we know whether the decompressor
        attempted to write to it */
-    Arrays.fill(dstBuf, (byte)127);
+    if (precision == 8)
+      Arrays.fill((byte[])dstBuf, (byte)127);
+    else if (precision == 12)
+      Arrays.fill((short[])dstBuf, (short)2047);
+    else
+      Arrays.fill((short[])dstBuf, (short)32767);
 
     if (doYUV) {
       int width = doTile ? tilew : scaledw;
       int height = doTile ? tileh : scaledh;
 
-      yuvImage = new YUVImage(width, yuvPad, height, subsamp);
+      yuvImage = new YUVImage(width, yuvAlign, height, subsamp);
       Arrays.fill(yuvImage.getBuf(), (byte)127);
     }
 
@@ -209,23 +236,29 @@ final class TJBench {
           int height = doTile ? Math.min(tileh, h - y) : scaledh;
 
           try {
-            tjd.setSourceImage(jpegBuf[tile], jpegSize[tile]);
+            tjd.setSourceImage(jpegBufs[tile], jpegSizes[tile]);
           } catch (TJException e) { handleTJException(e); }
           if (doYUV) {
-            yuvImage.setBuf(yuvImage.getBuf(), width, yuvPad, height, subsamp);
+            yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height,
+                            subsamp);
             try {
-              tjd.decompressToYUV(yuvImage, flags);
+              tjd.decompressToYUV(yuvImage);
             } catch (TJException e) { handleTJException(e); }
             double startDecode = getTime();
             tjd.setSourceImage(yuvImage);
             try {
-              tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags);
+              tjd.decompress8((byte[])dstBuf, x, y, pitch, pf);
             } catch (TJException e) { handleTJException(e); }
             if (iter >= 0)
               elapsedDecode += getTime() - startDecode;
           } else {
             try {
-              tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags);
+              if (precision == 8)
+                tjd.decompress8((byte[])dstBuf, x, y, pitch, pf);
+              else if (precision == 12)
+                tjd.decompress12((short[])dstBuf, x, y, pitch, pf);
+              else
+                tjd.decompress16((short[])dstBuf, x, y, pitch, pf);
             } catch (TJException e) { handleTJException(e); }
           }
         }
@@ -243,10 +276,9 @@ final class TJBench {
     if (doYUV)
       elapsed -= elapsedDecode;
 
-    tjd = null;
-    for (i = 0; i < jpegBuf.length; i++)
-      jpegBuf[i] = null;
-    jpegBuf = null;  jpegSize = null;
+    for (i = 0; i < jpegBufs.length; i++)
+      jpegBufs[i] = null;
+    jpegBufs = null;  jpegSizes = null;
     System.gc();
 
     if (quiet != 0) {
@@ -284,52 +316,22 @@ final class TJBench {
     else
       sizeStr = new String("full");
     if (decompOnly)
-      tempStr = new String(fileName + "_" + sizeStr + ".bmp");
+      tempStr = new String(fileName + "_" + sizeStr + (bmp ? ".bmp" : ".ppm"));
     else
-      tempStr = new String(fileName + "_" + SUBNAME[subsamp] + qualStr +
-                           "_" + sizeStr + ".bmp");
-
-    saveImage(tempStr, dstBuf, scaledw, scaledh, pf);
-    int ndx = tempStr.lastIndexOf('.');
-    tempStr = new String(tempStr.substring(0, ndx) + "-err.bmp");
-    if (srcBuf != null && sf.getNum() == 1 && sf.getDenom() == 1) {
-      if (quiet == 0)
-        System.out.println("Compression error written to " + tempStr + ".");
-      if (subsamp == TJ.SAMP_GRAY) {
-        for (int y = 0, index = 0; y < h; y++, index += pitch) {
-          for (int x = 0, index2 = index; x < w; x++, index2 += ps) {
-            int rindex = index2 + TJ.getRedOffset(pf);
-            int gindex = index2 + TJ.getGreenOffset(pf);
-            int bindex = index2 + TJ.getBlueOffset(pf);
-            int lum = (int)((double)(srcBuf[rindex] & 0xff) * 0.299 +
-                            (double)(srcBuf[gindex] & 0xff) * 0.587 +
-                            (double)(srcBuf[bindex] & 0xff) * 0.114 + 0.5);
-
-            if (lum > 255) lum = 255;
-            if (lum < 0) lum = 0;
-            dstBuf[rindex] = (byte)Math.abs((dstBuf[rindex] & 0xff) - lum);
-            dstBuf[gindex] = (byte)Math.abs((dstBuf[gindex] & 0xff) - lum);
-            dstBuf[bindex] = (byte)Math.abs((dstBuf[bindex] & 0xff) - lum);
-          }
-        }
-      } else {
-        for (int y = 0; y < h; y++)
-          for (int x = 0; x < w * ps; x++)
-            dstBuf[pitch * y + x] =
-              (byte)Math.abs((dstBuf[pitch * y + x] & 0xff) -
-                             (srcBuf[pitch * y + x] & 0xff));
-      }
-      saveImage(tempStr, dstBuf, w, h, pf);
-    }
+      tempStr = new String(fileName + "_" +
+                           (lossless ? "LOSSLS" : SUBNAME[subsamp]) + qualStr +
+                           "_" + sizeStr + (bmp ? ".bmp" : ".ppm"));
+
+    tjd.saveImage(precision, tempStr, dstBuf, scaledw, 0, scaledh, pf);
   }
 
 
-  static void fullTest(byte[] srcBuf, int w, int h, int subsamp, int jpegQual,
-                       String fileName) throws Exception {
-    TJCompressor tjc;
-    byte[] tmpBuf;
-    byte[][] jpegBuf;
-    int[] jpegSize;
+  static void fullTest(TJCompressor tjc, Object srcBuf, int w, int h,
+                       int subsamp, int jpegQual, String fileName)
+                       throws Exception {
+    Object tmpBuf;
+    byte[][] jpegBufs;
+    int[] jpegSizes;
     double start, elapsed, elapsedEncode;
     int totalJpegSize = 0, tilew, tileh, i, iter;
     int ps = TJ.getPixelSize(pf);
@@ -339,15 +341,29 @@ final class TJBench {
 
     if ((long)pitch * (long)h > (long)Integer.MAX_VALUE)
       throw new Exception("Image is too large");
-    tmpBuf = new byte[pitch * h];
+    if (precision == 8)
+      tmpBuf = new byte[pitch * h];
+    else
+      tmpBuf = new short[pitch * h];
 
     if (quiet == 0)
-      System.out.format(">>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n", pfStr,
-                        (flags & TJ.FLAG_BOTTOMUP) != 0 ?
-                        "Bottom-up" : "Top-down",
-                        SUBNAME_LONG[subsamp], jpegQual);
-
-    tjc = new TJCompressor();
+      System.out.format(">>>>>  %s (%s) <--> %d-bit JPEG (%s %s%d)  <<<<<\n",
+                        pfStr, bottomUp ? "Bottom-up" : "Top-down", precision,
+                        lossless ? "Lossless" : SUBNAME_LONG[subsamp],
+                        lossless ? "PSV" : "Q", jpegQual);
+
+    tjc.set(TJ.PARAM_SUBSAMP, subsamp);
+    tjc.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
+    tjc.set(TJ.PARAM_OPTIMIZE, optimize ? 1 : 0);
+    tjc.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0);
+    tjc.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0);
+    tjc.set(TJ.PARAM_LOSSLESS, lossless ? 1 : 0);
+    if (lossless)
+      tjc.set(TJ.PARAM_LOSSLESSPSV, jpegQual);
+    else
+      tjc.set(TJ.PARAM_QUALITY, jpegQual);
+    tjc.set(TJ.PARAM_RESTARTBLOCKS, restartIntervalBlocks);
+    tjc.set(TJ.PARAM_RESTARTROWS, restartIntervalRows);
 
     for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
          tilew *= 2, tileh *= 2) {
@@ -358,21 +374,28 @@ final class TJBench {
       ntilesw = (w + tilew - 1) / tilew;
       ntilesh = (h + tileh - 1) / tileh;
 
-      jpegBuf = new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)];
-      jpegSize = new int[ntilesw * ntilesh];
+      jpegBufs =
+        new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)];
+      jpegSizes = new int[ntilesw * ntilesh];
 
       /* Compression test */
       if (quiet == 1)
-        System.out.format("%-4s (%s)  %-5s    %-3d   ", pfStr,
-                          (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD",
-                          SUBNAME_LONG[subsamp], jpegQual);
-      for (i = 0; i < h; i++)
-        System.arraycopy(srcBuf, w * ps * i, tmpBuf, pitch * i, w * ps);
-      tjc.setJPEGQuality(jpegQual);
-      tjc.setSubsamp(subsamp);
+        System.out.format("%-4s(%s)  %-2d/%-6s %-3d   ", pfStr,
+                          bottomUp ? "BU" : "TD", precision,
+                          lossless ? "LOSSLS" : SUBNAME_LONG[subsamp],
+                          jpegQual);
+      if (precision == 8) {
+        for (i = 0; i < h; i++)
+          System.arraycopy((byte[])srcBuf, w * ps * i, (byte[])tmpBuf,
+                           pitch * i, w * ps);
+      } else {
+        for (i = 0; i < h; i++)
+          System.arraycopy((short[])srcBuf, w * ps * i, (short[])tmpBuf,
+                           pitch * i, w * ps);
+      }
 
       if (doYUV) {
-        yuvImage = new YUVImage(tilew, yuvPad, tileh, subsamp);
+        yuvImage = new YUVImage(tilew, yuvAlign, tileh, subsamp);
         Arrays.fill(yuvImage.getBuf(), (byte)127);
       }
 
@@ -389,20 +412,28 @@ final class TJBench {
             int width = Math.min(tilew, w - x);
             int height = Math.min(tileh, h - y);
 
-            tjc.setSourceImage(srcBuf, x, y, width, pitch, height, pf);
+            if (precision == 8)
+              tjc.setSourceImage((byte[])srcBuf, x, y, width, pitch, height,
+                                 pf);
+            else if (precision == 12)
+              tjc.setSourceImage12((short[])srcBuf, x, y, width, pitch, height,
+                                   pf);
+            else
+              tjc.setSourceImage16((short[])srcBuf, x, y, width, pitch, height,
+                                   pf);
             if (doYUV) {
               double startEncode = getTime();
 
-              yuvImage.setBuf(yuvImage.getBuf(), width, yuvPad, height,
+              yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height,
                               subsamp);
-              tjc.encodeYUV(yuvImage, flags);
+              tjc.encodeYUV(yuvImage);
               if (iter >= 0)
                 elapsedEncode += getTime() - startEncode;
               tjc.setSourceImage(yuvImage);
             }
-            tjc.compress(jpegBuf[tile], flags);
-            jpegSize[tile] = tjc.getCompressedSize();
-            totalJpegSize += jpegSize[tile];
+            tjc.compress(jpegBufs[tile]);
+            jpegSizes[tile] = tjc.getCompressedSize();
+            totalJpegSize += jpegSizes[tile];
           }
         }
         elapsed += getTime() - start;
@@ -465,11 +496,12 @@ final class TJBench {
                           (double)iter / elapsed);
       }
       if (tilew == w && tileh == h && write) {
-        String tempStr = fileName + "_" + SUBNAME[subsamp] + "_" + "Q" +
-                         jpegQual + ".jpg";
+        String tempStr = fileName + "_" +
+                         (lossless ? "LOSSLS" : SUBNAME[subsamp]) + "_" +
+                         (lossless ? "PSV" : "Q") + jpegQual + ".jpg";
         FileOutputStream fos = new FileOutputStream(tempStr);
 
-        fos.write(jpegBuf[0], 0, jpegSize[0]);
+        fos.write(jpegBufs[0], 0, jpegSizes[0]);
         fos.close();
         if (quiet == 0)
           System.out.println("Reference image written to " + tempStr);
@@ -477,8 +509,8 @@ final class TJBench {
 
       /* Decompression test */
       if (!compOnly)
-        decomp(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
-               fileName, tilew, tileh);
+        decomp(jpegBufs, jpegSizes, tmpBuf, w, h, subsamp, jpegQual, fileName,
+               tilew, tileh);
       else if (quiet == 1)
         System.out.println("N/A");
 
@@ -489,16 +521,16 @@ final class TJBench {
 
   static void decompTest(String fileName) throws Exception {
     TJTransformer tjt;
-    byte[][] jpegBuf = null;
+    byte[][] jpegBufs = null;
     byte[] srcBuf;
-    int[] jpegSize = null;
+    int[] jpegSizes = null;
     int totalJpegSize;
     double start, elapsed;
     int ps = TJ.getPixelSize(pf), tile, x, y, iter;
     // Original image
     int w = 0, h = 0, ntilesw = 1, ntilesh = 1, subsamp = -1, cs = -1;
     // Transformed image
-    int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
+    int minTile = 16, tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
 
     FileInputStream fis = new FileInputStream(fileName);
     if (fis.getChannel().size() > (long)Integer.MAX_VALUE)
@@ -513,34 +545,60 @@ final class TJBench {
       fileName = new String(fileName.substring(0, index));
 
     tjt = new TJTransformer();
+    tjt.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
+    tjt.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
+    tjt.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0);
+    tjt.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
+    tjt.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0);
 
     try {
       tjt.setSourceImage(srcBuf, srcSize);
     } catch (TJException e) { handleTJException(e); }
     w = tjt.getWidth();
     h = tjt.getHeight();
-    subsamp = tjt.getSubsamp();
-    cs = tjt.getColorspace();
+    subsamp = tjt.get(TJ.PARAM_SUBSAMP);
+    precision = tjt.get(TJ.PARAM_PRECISION);
+    cs = tjt.get(TJ.PARAM_COLORSPACE);
+    if (tjt.get(TJ.PARAM_PROGRESSIVE) == 1)
+      System.out.println("JPEG image uses progressive entropy coding\n");
+    if (tjt.get(TJ.PARAM_ARITHMETIC) == 1)
+      System.out.println("JPEG image uses arithmetic entropy coding\n");
+    tjt.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0);
+    tjt.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0);
+
+    if (cs == TJ.CS_YCCK || cs == TJ.CS_CMYK) {
+      pf = TJ.PF_CMYK;  ps = TJ.getPixelSize(pf);
+    }
+
+    if (tjt.get(TJ.PARAM_LOSSLESS) != 0)
+      sf = TJ.UNSCALED;
+
+    tjt.setScalingFactor(sf);
+    tjt.setCroppingRegion(cr);
 
     if (quiet == 1) {
       System.out.println("All performance values in Mpixels/sec\n");
-      System.out.format("Bitmap     JPEG   JPEG     %s  %s   Xform   Comp    Decomp  ",
+      System.out.format("Pixel     JPEG             %s  %s   Xform   Comp    Decomp  ",
                         (doTile ? "Tile " : "Image"),
                         (doTile ? "Tile " : "Image"));
       if (doYUV)
         System.out.print("Decode");
       System.out.print("\n");
-      System.out.print("Format     CS     Subsamp  Width  Height  Perf    Ratio   Perf    ");
+      System.out.print("Format    Format           Width  Height  Perf    Ratio   Perf    ");
       if (doYUV)
         System.out.print("Perf");
       System.out.println("\n");
     } else if (quiet == 0)
-      System.out.format(">>>>>  JPEG %s --> %s (%s)  <<<<<\n",
-                        formatName(subsamp, cs), PIXFORMATSTR[pf],
-                        (flags & TJ.FLAG_BOTTOMUP) != 0 ?
-                        "Bottom-up" : "Top-down");
-
-    for (int tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
+      System.out.format(">>>>>  %d-bit JPEG (%s) --> %s (%s)  <<<<<\n",
+                        precision, formatName(subsamp, cs), PIXFORMATSTR[pf],
+                        bottomUp ? "Bottom-up" : "Top-down");
+
+    if (doTile) {
+      if (subsamp == TJ.SAMP_UNKNOWN)
+        throw new Exception("Could not determine subsampling level of JPEG image");
+      minTile = Math.max(TJ.getMCUWidth(subsamp), TJ.getMCUHeight(subsamp));
+    }
+    for (int tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ;
          tilew *= 2, tileh *= 2) {
       if (tilew > w)
         tilew = w;
@@ -553,19 +611,20 @@ final class TJBench {
       if (quiet == 0) {
         System.out.format("\n%s size: %d x %d", (doTile ? "Tile" : "Image"),
                           ttilew, ttileh);
-        if (sf.getNum() != 1 || sf.getDenom() != 1)
-          System.out.format(" --> %d x %d", sf.getScaled(tw),
-                            sf.getScaled(th));
+        if (sf.getNum() != 1 || sf.getDenom() != 1 || isCropped(cr))
+          System.out.format(" --> %d x %d", getCroppedWidth(tw),
+                            getCroppedHeight(th));
         System.out.println("");
       } else if (quiet == 1) {
-        System.out.format("%-4s (%s)  %-5s  %-5s    ", PIXFORMATSTR[pf],
-                          (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD",
-                          CSNAME[cs], SUBNAME_LONG[subsamp]);
-        System.out.format("%-5d  %-5d   ", tilew, tileh);
+        System.out.format("%-4s(%s)  %-14s   ", PIXFORMATSTR[pf],
+                          bottomUp ? "BU" : "TD", formatName(subsamp, cs));
+        System.out.format("%-5d  %-5d   ", getCroppedWidth(tilew),
+                          getCroppedHeight(tileh));
       }
 
       tsubsamp = subsamp;
-      if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0) {
+      if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0 ||
+          customFilter != null) {
         if (xformOp == TJTransform.OP_TRANSPOSE ||
             xformOp == TJTransform.OP_TRANSVERSE ||
             xformOp == TJTransform.OP_ROT90 ||
@@ -573,6 +632,9 @@ final class TJBench {
           tw = h;  th = w;  ttilew = tileh;  ttileh = tilew;
         }
 
+        if (xformOp != TJTransform.OP_NONE &&
+            xformOp != TJTransform.OP_TRANSPOSE && subsamp == TJ.SAMP_UNKNOWN)
+          throw new Exception("Could not determine subsampling level of JPEG image");
         if ((xformOpt & TJTransform.OPT_GRAY) != 0)
           tsubsamp = TJ.SAMP_GRAY;
         if (xformOp == TJTransform.OP_HFLIP ||
@@ -598,10 +660,14 @@ final class TJBench {
             tsubsamp = TJ.SAMP_440;
           else if (tsubsamp == TJ.SAMP_440)
             tsubsamp = TJ.SAMP_422;
+          else if (tsubsamp == TJ.SAMP_411)
+            tsubsamp = TJ.SAMP_441;
+          else if (tsubsamp == TJ.SAMP_441)
+            tsubsamp = TJ.SAMP_411;
         }
 
         TJTransform[] t = new TJTransform[tntilesw * tntilesh];
-        jpegBuf =
+        jpegBufs =
           new byte[tntilesw * tntilesh][TJ.bufSize(ttilew, ttileh, subsamp)];
 
         for (y = 0, tile = 0; y < th; y += ttileh) {
@@ -613,9 +679,10 @@ final class TJBench {
             t[tile].y = y;
             t[tile].op = xformOp;
             t[tile].options = xformOpt | TJTransform.OPT_TRIM;
+            t[tile].cf = customFilter;
             if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 &&
-                jpegBuf[tile] != null)
-              jpegBuf[tile] = null;
+                jpegBufs[tile] != null)
+              jpegBufs[tile] = null;
           }
         }
 
@@ -624,9 +691,9 @@ final class TJBench {
         while (true) {
           start = getTime();
           try {
-            tjt.transform(jpegBuf, t, flags);
+            tjt.transform(jpegBufs, t);
           } catch (TJException e) { handleTJException(e); }
-          jpegSize = tjt.getTransformedSizes();
+          jpegSizes = tjt.getTransformedSizes();
           elapsed += getTime() - start;
           if (iter >= 0) {
             iter++;
@@ -640,7 +707,7 @@ final class TJBench {
         t = null;
 
         for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
-          totalJpegSize += jpegSize[tile];
+          totalJpegSize += jpegSizes[tile];
 
         if (quiet != 0) {
           System.out.format("%-6s%s%-6s%s",
@@ -664,10 +731,10 @@ final class TJBench {
       } else {
         if (quiet == 1)
           System.out.print("N/A     N/A     ");
-        jpegBuf = new byte[1][TJ.bufSize(ttilew, ttileh, subsamp)];
-        jpegSize = new int[1];
-        jpegBuf[0] = srcBuf;
-        jpegSize[0] = srcSize;
+        jpegBufs = new byte[1][TJ.bufSize(ttilew, ttileh, subsamp)];
+        jpegSizes = new int[1];
+        jpegBufs[0] = srcBuf;
+        jpegSizes[0] = srcSize;
       }
 
       if (w == tilew)
@@ -675,13 +742,13 @@ final class TJBench {
       if (h == tileh)
         ttileh = th;
       if ((xformOpt & TJTransform.OPT_NOOUTPUT) == 0)
-        decomp(null, jpegBuf, jpegSize, null, tw, th, tsubsamp, 0,
-               fileName, ttilew, ttileh);
+        decomp(jpegBufs, jpegSizes, null, tw, th, tsubsamp, 0, fileName,
+               ttilew, ttileh);
       else if (quiet == 1)
         System.out.println("N/A");
 
-      jpegBuf = null;
-      jpegSize = null;
+      jpegBufs = null;
+      jpegSizes = null;
 
       if (tilew == w && tileh == h) break;
     }
@@ -695,34 +762,62 @@ final class TJBench {
     String className = new TJBench().getClass().getName();
 
     System.out.println("\nUSAGE: java " + className);
-    System.out.println("       <Inputfile (BMP)> <Quality> [options]\n");
+    System.out.println("       <Inputimage (BMP|PPM)> <Quality or PSV> [options]\n");
     System.out.println("       java " + className);
-    System.out.println("       <Inputfile (JPG)> [options]\n");
-    System.out.println("Options:\n");
-    System.out.println("-alloc = Dynamically allocate JPEG image buffers");
-    System.out.println("-bottomup = Test bottom-up compression/decompression");
-    System.out.println("-tile = Test performance of the codec when the image is encoded as separate");
-    System.out.println("     tiles of varying sizes.");
+    System.out.println("       <Inputimage (JPG)> [options]");
+
+    System.out.println("\nGENERAL OPTIONS");
+    System.out.println("---------------");
+    System.out.println("-benchtime T = Run each benchmark for at least T seconds [default = 5.0]");
+    System.out.println("-bmp = Use Windows Bitmap format for output images [default = PPM]");
+    System.out.println("     ** 8-bit data precision only **");
+    System.out.println("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers");
+    System.out.println("-componly = Stop after running compression tests.  Do not test decompression.");
+    System.out.println("-lossless = Generate lossless JPEG images when compressing (implies");
+    System.out.println("     -subsamp 444).  PSV is the predictor selection value (1-7).");
+    System.out.println("-nowrite = Do not write reference or output images (improves consistency of");
+    System.out.println("     benchmark results)");
     System.out.println("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =");
-    System.out.println("     Test the specified color conversion path in the codec (default = BGR)");
-    System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in");
-    System.out.println("     the underlying codec");
-    System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying");
-    System.out.println("     codec");
-    System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the");
-    System.out.println("     underlying codec");
-    System.out.println("-progressive = Use progressive entropy coding in JPEG images generated by");
-    System.out.println("     compression and transform operations.");
-    System.out.println("-subsamp <s> = When testing JPEG compression, this option specifies the level");
-    System.out.println("     of chrominance subsampling to use (<s> = 444, 422, 440, 420, 411, or");
-    System.out.println("     GRAY).  The default is to test Grayscale, 4:2:0, 4:2:2, and 4:4:4 in");
-    System.out.println("     sequence.");
+    System.out.println("     Use the specified pixel format for packed-pixel source/destination buffers");
+    System.out.println("     [default = BGR]");
+    System.out.println("-cmyk = Indirectly test YCCK JPEG compression/decompression");
+    System.out.println("     (use the CMYK pixel format for packed-pixel source/destination buffers)");
+    System.out.println("-precision N = Use N-bit data precision when compressing [N is 8, 12, or 16;");
+    System.out.println("     default = 8; if N is 16, then -lossless must also be specified]");
+    System.out.println("     (-precision 12 implies -optimize unless -arithmetic is also specified)");
     System.out.println("-quiet = Output results in tabular rather than verbose format");
-    System.out.println("-yuv = Test YUV encoding/decoding functions");
-    System.out.println("-yuvpad <p> = If testing YUV encoding/decoding, this specifies the number of");
-    System.out.println("     bytes to which each row of each plane in the intermediate YUV image is");
-    System.out.println("     padded (default = 1)");
-    System.out.println("-scale M/N = Scale down the width/height of the decompressed JPEG image by a");
+    System.out.println("-restart N = When compressing, add a restart marker every N MCU rows (lossy) or");
+    System.out.println("     N sample rows (lossless) [default = 0 (no restart markers)].  Append 'B'");
+    System.out.println("     to specify the restart marker interval in MCU blocks (lossy) or samples");
+    System.out.println("     (lossless).");
+    System.out.println("-stoponwarning = Immediately discontinue the current");
+    System.out.println("     compression/decompression/transform operation if a warning (non-fatal");
+    System.out.println("     error) occurs");
+    System.out.println("-tile = Compress/transform the input image into separate JPEG tiles of varying");
+    System.out.println("     sizes (useful for measuring JPEG overhead)");
+    System.out.println("-warmup T = Run each benchmark for T seconds [default = 1.0] prior to starting");
+    System.out.println("     the timer, in order to prime the caches and thus improve the consistency");
+    System.out.println("     of the benchmark results");
+
+    System.out.println("\nLOSSY JPEG OPTIONS");
+    System.out.println("------------------");
+    System.out.println("-arithmetic = Use arithmetic entropy coding in JPEG images generated by");
+    System.out.println("     compression and transform operations (can be combined with -progressive)");
+    System.out.println("-crop WxH+X+Y = Decompress only the specified region of the JPEG image, where W");
+    System.out.println("     and H are the width and height of the region (0 = maximum possible width");
+    System.out.println("     or height) and X and Y are the left and upper boundary of the region, all");
+    System.out.println("     specified relative to the scaled image dimensions.  X must be divible by");
+    System.out.println("     the scaled MCU width.");
+    System.out.println("-fastdct = Use the fastest DCT/IDCT algorithm available");
+    System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available");
+    System.out.println("-optimize = Use optimized baseline entropy coding in JPEG images generated by");
+    System.out.println("     compession and transform operations");
+    System.out.println("-progressive = Use progressive entropy coding in JPEG images generated by");
+    System.out.println("     compression and transform operations (can be combined with -arithmetic;");
+    System.out.println("     implies -optimize unless -arithmetic is also specified)");
+    System.out.println("-limitscans = Refuse to decompress or transform progressive JPEG images that");
+    System.out.println("     have an unreasonably large number of scans");
+    System.out.println("-scale M/N = When decompressing, scale the width/height of the JPEG image by a");
     System.out.print("     factor of M/N (M/N = ");
     for (i = 0; i < nsf; i++) {
       System.out.format("%d/%d", scalingFactors[i].getNum(),
@@ -739,36 +834,34 @@ final class TJBench {
         System.out.print("\n     ");
     }
     System.out.println(")");
+    System.out.println("-subsamp S = When compressing, use the specified level of chrominance");
+    System.out.println("     subsampling (S = 444, 422, 440, 420, 411, 441, or GRAY) [default = test");
+    System.out.println("     Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]");
     System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
-    System.out.println("     Perform the corresponding lossless transform prior to");
-    System.out.println("     decompression (these options are mutually exclusive)");
-    System.out.println("-grayscale = Perform lossless grayscale conversion prior to decompression");
-    System.out.println("     test (can be combined with the other transforms above)");
+    System.out.println("     Perform the specified lossless transform operation on the input image");
+    System.out.println("     prior to decompression (these operations are mutually exclusive)");
+    System.out.println("-grayscale = Transform the input image into a grayscale JPEG image prior to");
+    System.out.println("     decompression (can be combined with the other transform operations above)");
     System.out.println("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)");
-    System.out.println("     when transforming the image.");
-    System.out.println("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)");
-    System.out.println("-warmup <t> = Run each benchmark for <t> seconds (default = 1.0) prior to");
-    System.out.println("     starting the timer, in order to prime the caches and thus improve the");
-    System.out.println("     consistency of the results.");
-    System.out.println("-componly = Stop after running compression tests.  Do not test decompression.");
-    System.out.println("-nowrite = Do not write reference or output images (improves consistency");
-    System.out.println("     of performance measurements.)");
-    System.out.println("-limitscans = Refuse to decompress or transform progressive JPEG images that");
-    System.out.println("     have an unreasonably large number of scans");
-    System.out.println("-stoponwarning = Immediately discontinue the current");
-    System.out.println("     compression/decompression/transform operation if the underlying codec");
-    System.out.println("     throws a warning (non-fatal error)\n");
-    System.out.println("NOTE:  If the quality is specified as a range (e.g. 90-100), a separate");
-    System.out.println("test will be performed for all quality values in the range.\n");
+    System.out.println("     when transforming the input image");
+    System.out.println("-yuv = Compress from/decompress to intermediate planar YUV images");
+    System.out.println("     ** 8-bit data precision only **");
+    System.out.println("-yuvpad N = The number of bytes by which each row in each plane of an");
+    System.out.println("     intermediate YUV image is evenly divisible (N must be a power of 2)");
+    System.out.println("     [default = 1]");
+
+    System.out.println("\nNOTE:  If the quality/PSV is specified as a range (e.g. 90-100 or 1-4), a");
+    System.out.println("separate test will be performed for all values in the range.\n");
     System.exit(1);
   }
 
 
   public static void main(String[] argv) {
-    byte[] srcBuf = null;
+    Object srcBuf = null;
     int w = 0, h = 0, minQual = -1, maxQual = -1;
     int minArg = 1, retval = 0;
     int subsamp = -1;
+    TJCompressor tjc = null;
 
     try {
 
@@ -778,6 +871,8 @@ final class TJBench {
       String tempStr = argv[0].toLowerCase();
       if (tempStr.endsWith(".jpg") || tempStr.endsWith(".jpeg"))
         decompOnly = true;
+      if (tempStr.endsWith(".bmp"))
+        bmp = true;
 
       System.out.println("");
 
@@ -785,18 +880,16 @@ final class TJBench {
         minArg = 2;
         if (argv.length < minArg)
           usage();
+        String[] quals = argv[1].split("-", 2);
         try {
-          minQual = Integer.parseInt(argv[1]);
+          minQual = Integer.parseInt(quals[0]);
         } catch (NumberFormatException e) {}
-        if (minQual < 1 || minQual > 100)
-          throw new Exception("Quality must be between 1 and 100.");
-        int dashIndex = argv[1].indexOf('-');
-        if (dashIndex > 0 && argv[1].length() > dashIndex + 1) {
+        if (quals.length > 1) {
           try {
-            maxQual = Integer.parseInt(argv[1].substring(dashIndex + 1));
+            maxQual = Integer.parseInt(quals[1]);
           } catch (NumberFormatException e) {}
         }
-        if (maxQual < 1 || maxQual > 100)
+        if (maxQual < minQual)
           maxQual = minQual;
       }
 
@@ -804,18 +897,38 @@ final class TJBench {
         for (int i = minArg; i < argv.length; i++) {
           if (argv[i].equalsIgnoreCase("-tile")) {
             doTile = true;  xformOpt |= TJTransform.OPT_CROP;
+          } else if (argv[i].equalsIgnoreCase("-precision") &&
+                     i < argv.length - 1) {
+            int temp = 0;
+
+            try {
+              temp = Integer.parseInt(argv[++i]);
+            } catch (NumberFormatException e) {}
+            if (temp == 8 || temp == 12 || temp == 16)
+              precision = temp;
+            else
+              usage();
           } else if (argv[i].equalsIgnoreCase("-fastupsample")) {
-            System.out.println("Using fast upsampling code\n");
-            flags |= TJ.FLAG_FASTUPSAMPLE;
+            System.out.println("Using fastest upsampling algorithm\n");
+            fastUpsample = true;
           } else if (argv[i].equalsIgnoreCase("-fastdct")) {
             System.out.println("Using fastest DCT/IDCT algorithm\n");
-            flags |= TJ.FLAG_FASTDCT;
-          } else if (argv[i].equalsIgnoreCase("-accuratedct")) {
-            System.out.println("Using most accurate DCT/IDCT algorithm\n");
-            flags |= TJ.FLAG_ACCURATEDCT;
+            fastDCT = true;
+          } else if (argv[i].equalsIgnoreCase("-optimize")) {
+            System.out.println("Using optimized baseline entropy coding\n");
+            optimize = true;
+            xformOpt |= TJTransform.OPT_OPTIMIZE;
           } else if (argv[i].equalsIgnoreCase("-progressive")) {
             System.out.println("Using progressive entropy coding\n");
-            flags |= TJ.FLAG_PROGRESSIVE;
+            progressive = true;
+            xformOpt |= TJTransform.OPT_PROGRESSIVE;
+          } else if (argv[i].equalsIgnoreCase("-arithmetic")) {
+            System.out.println("Using arithmetic entropy coding\n");
+            arithmetic = true;
+            xformOpt |= TJTransform.OPT_ARITHMETIC;
+          } else if (argv[i].equalsIgnoreCase("-lossless")) {
+            lossless = true;
+            subsamp = TJ.SAMP_444;
           } else if (argv[i].equalsIgnoreCase("-rgb"))
             pf = TJ.PF_RGB;
           else if (argv[i].equalsIgnoreCase("-rgbx"))
@@ -828,8 +941,10 @@ final class TJBench {
             pf = TJ.PF_XBGR;
           else if (argv[i].equalsIgnoreCase("-xrgb"))
             pf = TJ.PF_XRGB;
+          else if (argv[i].equalsIgnoreCase("-cmyk"))
+            pf = TJ.PF_CMYK;
           else if (argv[i].equalsIgnoreCase("-bottomup"))
-            flags |= TJ.FLAG_BOTTOMUP;
+            bottomUp = true;
           else if (argv[i].equalsIgnoreCase("-quiet"))
             quiet = 1;
           else if (argv[i].equalsIgnoreCase("-qq"))
@@ -858,6 +973,21 @@ final class TJBench {
               if (!match) usage();
             } else
               usage();
+          } else if (argv[i].equalsIgnoreCase("-crop") &&
+                     i < argv.length - 1) {
+            int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1;
+            Scanner scanner = new Scanner(argv[++i]).useDelimiter("x|\\+");
+
+            try {
+              temp1 = scanner.nextInt();
+              temp2 = scanner.nextInt();
+              temp3 = scanner.nextInt();
+              temp4 = scanner.nextInt();
+            } catch (Exception e) {}
+
+            if (temp1 < 0 || temp2 < 0 || temp3 < 0 || temp4 < 0)
+              usage();
+            cr.width = temp1;  cr.height = temp2;  cr.x = temp3;  cr.y = temp4;
           } else if (argv[i].equalsIgnoreCase("-hflip"))
             xformOp = TJTransform.OP_HFLIP;
           else if (argv[i].equalsIgnoreCase("-vflip"))
@@ -874,6 +1004,8 @@ final class TJBench {
             xformOp = TJTransform.OP_ROT270;
           else if (argv[i].equalsIgnoreCase("-grayscale"))
             xformOpt |= TJTransform.OPT_GRAY;
+          else if (argv[i].equalsIgnoreCase("-custom"))
+            customFilter = new DummyDCTFilter();
           else if (argv[i].equalsIgnoreCase("-nooutput"))
             xformOpt |= TJTransform.OPT_NOOUTPUT;
           else if (argv[i].equalsIgnoreCase("-copynone"))
@@ -901,8 +1033,10 @@ final class TJBench {
               System.out.format("Warmup time = %.1f seconds\n\n", warmup);
             } else
               usage();
-          } else if (argv[i].equalsIgnoreCase("-yuv")) {
-            System.out.println("Testing YUV planar encoding/decoding\n");
+          } else if (argv[i].equalsIgnoreCase("-bmp"))
+            bmp = true;
+          else if (argv[i].equalsIgnoreCase("-yuv")) {
+            System.out.println("Testing planar YUV encoding/decoding\n");
             doYUV = true;
           } else if (argv[i].equalsIgnoreCase("-yuvpad") &&
                      i < argv.length - 1) {
@@ -911,8 +1045,10 @@ final class TJBench {
             try {
               temp = Integer.parseInt(argv[++i]);
             } catch (NumberFormatException e) {}
-            if (temp >= 1)
-              yuvPad = temp;
+            if (temp >= 1 && (temp & (temp - 1)) == 0)
+              yuvAlign = temp;
+            else
+              usage();
           } else if (argv[i].equalsIgnoreCase("-subsamp") &&
                      i < argv.length - 1) {
             i++;
@@ -928,32 +1064,77 @@ final class TJBench {
               subsamp = TJ.SAMP_420;
             else if (argv[i].equals("411"))
               subsamp = TJ.SAMP_411;
+            else if (argv[i].equals("441"))
+              subsamp = TJ.SAMP_441;
+            else
+              usage();
           } else if (argv[i].equalsIgnoreCase("-componly"))
             compOnly = true;
           else if (argv[i].equalsIgnoreCase("-nowrite"))
             write = false;
           else if (argv[i].equalsIgnoreCase("-limitscans"))
-            flags |= TJ.FLAG_LIMITSCANS;
-          else if (argv[i].equalsIgnoreCase("-stoponwarning"))
-            flags |= TJ.FLAG_STOPONWARNING;
+            limitScans = true;
+          else if (argv[i].equalsIgnoreCase("-restart") &&
+                   i < argv.length - 1) {
+            int temp = -1;
+            String arg = argv[++i];
+            Scanner scanner = new Scanner(arg).useDelimiter("b|B");
+
+            try {
+              temp = scanner.nextInt();
+            } catch (Exception e) {}
+
+            if (temp < 0 || temp > 65535 || scanner.hasNext())
+              usage();
+            if (arg.endsWith("B") || arg.endsWith("b"))
+              restartIntervalBlocks = temp;
+            else
+              restartIntervalRows = temp;
+          } else if (argv[i].equalsIgnoreCase("-stoponwarning"))
+            stopOnWarning = true;
           else usage();
         }
       }
 
-      if (sf == null)
-        sf = new TJScalingFactor(1, 1);
+      if (precision == 16 && !lossless)
+        throw new Exception("-lossless must be specified along with -precision 16");
+      if (precision != 8 && doYUV)
+        throw new Exception("-yuv requires 8-bit data precision");
+      if (lossless && doYUV)
+        throw new Exception("ERROR: -lossless and -yuv are incompatible");
 
       if ((sf.getNum() != 1 || sf.getDenom() != 1) && doTile) {
         System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
-        System.out.println("work when scaled decompression is enabled.");
+        System.out.println("work when scaled decompression is enabled.\n");
         doTile = false;
+        xformOpt &= (~TJTransform.OPT_CROP);
+      }
+
+      if (isCropped(cr)) {
+        if (!decompOnly)
+          throw new Exception("ERROR: Partial image decompression can only be enabled for JPEG input images");
+        if (doTile) {
+          System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
+          System.out.println("work when partial image decompression is enabled.\n");
+          doTile = false;
+          xformOpt &= (~TJTransform.OPT_CROP);
+        }
+        if (doYUV)
+          throw new Exception("ERROR: -crop and -yuv are incompatible");
       }
 
       if (!decompOnly) {
-        int[] width = new int[1], height = new int[1];
+        int[] width = new int[1], height = new int[1],
+          pixelFormat = new int[1];
+
+        tjc = new TJCompressor();
+        tjc.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
+        tjc.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
 
-        srcBuf = loadImage(argv[0], width, height, pf);
-        w = width[0];  h = height[0];
+        pixelFormat[0] = pf;
+        srcBuf = tjc.loadImage(precision, argv[0], width, 1, height,
+                               pixelFormat);
+        w = width[0];  h = height[0];  pf = pixelFormat[0];
         int index = -1;
         if ((index = argv[0].lastIndexOf('.')) >= 0)
           argv[0] = argv[0].substring(0, index);
@@ -961,7 +1142,7 @@ final class TJBench {
 
       if (quiet == 1 && !decompOnly) {
         System.out.println("All performance values in Mpixels/sec\n");
-        System.out.format("Bitmap     JPEG     JPEG  %s  %s   ",
+        System.out.format("Pixel     JPEG      JPEG  %s  %s   ",
                           (doTile ? "Tile " : "Image"),
                           (doTile ? "Tile " : "Image"));
         if (doYUV)
@@ -970,7 +1151,8 @@ final class TJBench {
         if (doYUV)
           System.out.print("Decode");
         System.out.print("\n");
-        System.out.print("Format     Subsamp  Qual  Width  Height  ");
+        System.out.format("Format    Format    %s  Width  Height  ",
+                          lossless ? "PSV " : "Qual");
         if (doYUV)
           System.out.print("Perf    ");
         System.out.print("Perf    Ratio   Perf    ");
@@ -986,25 +1168,34 @@ final class TJBench {
       }
 
       System.gc();
+      if (lossless) {
+        if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7)
+          throw new Exception("PSV must be between 1 and 7.");
+      } else {
+        if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100)
+          throw new Exception("Quality must be between 1 and 100.");
+      }
       if (subsamp >= 0 && subsamp < TJ.NUMSAMP) {
         for (int i = maxQual; i >= minQual; i--)
-          fullTest(srcBuf, w, h, subsamp, i, argv[0]);
+          fullTest(tjc, srcBuf, w, h, subsamp, i, argv[0]);
         System.out.println("");
       } else {
+        if (pf != TJ.PF_CMYK) {
+          for (int i = maxQual; i >= minQual; i--)
+            fullTest(tjc, srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]);
+          System.out.println("");
+          System.gc();
+        }
         for (int i = maxQual; i >= minQual; i--)
-          fullTest(srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]);
-        System.out.println("");
-        System.gc();
-        for (int i = maxQual; i >= minQual; i--)
-          fullTest(srcBuf, w, h, TJ.SAMP_420, i, argv[0]);
+          fullTest(tjc, srcBuf, w, h, TJ.SAMP_420, i, argv[0]);
         System.out.println("");
         System.gc();
         for (int i = maxQual; i >= minQual; i--)
-          fullTest(srcBuf, w, h, TJ.SAMP_422, i, argv[0]);
+          fullTest(tjc, srcBuf, w, h, TJ.SAMP_422, i, argv[0]);
         System.out.println("");
         System.gc();
         for (int i = maxQual; i >= minQual; i--)
-          fullTest(srcBuf, w, h, TJ.SAMP_444, i, argv[0]);
+          fullTest(tjc, srcBuf, w, h, TJ.SAMP_444, i, argv[0]);
         System.out.println("");
       }
 
index 7859886..6a2148c 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C)2011-2012, 2014-2015, 2017-2018 D. R. Commander.
- *                                              All Rights Reserved.
+ * Copyright (C)2011-2012, 2014-2015, 2017-2018, 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:
@@ -52,7 +52,7 @@ class TJExample implements TJCustomFilter {
 
 
   static final String[] SUBSAMP_NAME = {
-    "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1"
+    "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1", "4:4:1"
   };
 
   static final String[] COLORSPACE_NAME = {
@@ -136,14 +136,9 @@ class TJExample implements TJCustomFilter {
     System.out.println("-display = Display output image (Output filename need not be specified in this");
     System.out.println("     case.)\n");
 
-    System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in");
-    System.out.println("     the underlying codec.\n");
+    System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available\n");
 
-    System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying");
-    System.out.println("     codec.\n");
-
-    System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the");
-    System.out.println("     underlying codec.\n");
+    System.out.println("-fastdct = Use the fastest DCT/IDCT algorithm available\n");
 
     System.exit(1);
   }
@@ -153,11 +148,10 @@ class TJExample implements TJCustomFilter {
 
     try {
 
-      TJScalingFactor scalingFactor = new TJScalingFactor(1, 1);
+      TJScalingFactor scalingFactor = TJ.UNSCALED;
       int outSubsamp = -1, outQual = -1;
       TJTransform xform = new TJTransform();
-      boolean display = false;
-      int flags = 0;
+      boolean display = false, fastUpsample = false, fastDCT = false;
       int width, height;
       String inFormat = "jpg", outFormat = "jpg";
       BufferedImage img = null;
@@ -247,13 +241,10 @@ class TJExample implements TJCustomFilter {
           display = true;
         else if (argv[i].equalsIgnoreCase("-fastupsample")) {
           System.out.println("Using fast upsampling code");
-          flags |= TJ.FLAG_FASTUPSAMPLE;
+          fastUpsample = true;
         } else if (argv[i].equalsIgnoreCase("-fastdct")) {
           System.out.println("Using fastest DCT/IDCT algorithm");
-          flags |= TJ.FLAG_FASTDCT;
-        } else if (argv[i].equalsIgnoreCase("-accuratedct")) {
-          System.out.println("Using most accurate DCT/IDCT algorithm");
-          flags |= TJ.FLAG_ACCURATEDCT;
+          fastDCT = true;
         } else usage();
       }
 
@@ -294,16 +285,21 @@ class TJExample implements TJCustomFilter {
           TJTransform[] xforms = new TJTransform[1];
           xforms[0] = xform;
           xforms[0].options |= TJTransform.OPT_TRIM;
-          TJDecompressor[] tjds = tjt.transform(xforms, 0);
+          TJDecompressor[] tjds = tjt.transform(xforms);
           tjd = tjds[0];
           tjt.close();
         } else
           tjd = new TJDecompressor(jpegBuf);
+        tjd.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0);
+        tjd.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
 
         width = tjd.getWidth();
         height = tjd.getHeight();
-        int inSubsamp = tjd.getSubsamp();
-        int inColorspace = tjd.getColorspace();
+        int inSubsamp = tjd.get(TJ.PARAM_SUBSAMP);
+        int inColorspace = tjd.get(TJ.PARAM_COLORSPACE);
+
+        if (tjd.get(TJ.PARAM_LOSSLESS) == 1)
+          scalingFactor = TJ.UNSCALED;
 
         System.out.println((doTransform ? "Transformed" : "Input") +
                            " Image (jpg):  " + width + " x " + height +
@@ -325,16 +321,16 @@ class TJExample implements TJCustomFilter {
         /* Scaling and/or a non-JPEG output image format and/or compression
            options have been selected, so we need to decompress the
            input/transformed image. */
+        tjd.setScalingFactor(scalingFactor);
         width = scalingFactor.getScaled(width);
         height = scalingFactor.getScaled(height);
         if (outSubsamp < 0)
           outSubsamp = inSubsamp;
 
         if (!outFormat.equalsIgnoreCase("jpg"))
-          img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB,
-                               flags);
+          img = tjd.decompress8(BufferedImage.TYPE_INT_RGB);
         else
-          imgBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, flags);
+          imgBuf = tjd.decompress8(0, TJ.PF_BGRX);
         tjd.close();
       } else {
         /* Input image is not a JPEG image.  Load it into memory. */
@@ -371,13 +367,14 @@ class TJExample implements TJCustomFilter {
                            " subsampling, quality = " + outQual);
 
         TJCompressor tjc = new TJCompressor();
-        tjc.setSubsamp(outSubsamp);
-        tjc.setJPEGQuality(outQual);
+        tjc.set(TJ.PARAM_SUBSAMP, outSubsamp);
+        tjc.set(TJ.PARAM_QUALITY, outQual);
+        tjc.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
         if (img != null)
           tjc.setSourceImage(img, 0, 0, 0, 0);
         else
           tjc.setSourceImage(imgBuf, 0, 0, width, 0, height, TJ.PF_BGRX);
-        byte[] jpegBuf = tjc.compress(flags);
+        byte[] jpegBuf = tjc.compress();
         int jpegSize = tjc.getCompressedSize();
         tjc.close();
 
index 91ad5fd..6083928 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2018 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2018, 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:
@@ -48,18 +48,22 @@ final class TJUnitTest {
   static void usage() {
     System.out.println("\nUSAGE: java " + CLASS_NAME + " [options]\n");
     System.out.println("Options:");
-    System.out.println("-yuv = test YUV encoding/decoding support");
-    System.out.println("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest");
-    System.out.println("            4-byte boundary");
-    System.out.println("-bi = test BufferedImage support\n");
+    System.out.println("-yuv = test YUV encoding/compression/decompression/decoding");
+    System.out.println("       (8-bit data precision only)");
+    System.out.println("-noyuvpad = do not pad each row in each Y, U, and V plane to the nearest");
+    System.out.println("            multiple of 4 bytes");
+    System.out.println("-precision N = test N-bit data precision (N is 8, 12, or 16; default is 8; if N");
+    System.out.println("               is 16, then -lossless is implied)");
+    System.out.println("-lossless = test lossless JPEG compression/decompression");
+    System.out.println("-bi = test BufferedImage I/O (8-bit data precision only)\n");
     System.exit(1);
   }
 
   static final String[] SUBNAME_LONG = {
-    "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
+    "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
   };
   static final String[] SUBNAME = {
-    "444", "422", "420", "GRAY", "440", "411"
+    "444", "422", "420", "GRAY", "440", "411", "441"
   };
 
   static final String[] PIXFORMATSTR = {
@@ -67,13 +71,13 @@ final class TJUnitTest {
     "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
   };
 
-  static final int[] FORMATS_3BYTE = {
+  static final int[] FORMATS_3SAMPLE = {
     TJ.PF_RGB, TJ.PF_BGR
   };
   static final int[] FORMATS_3BYTEBI = {
     BufferedImage.TYPE_3BYTE_BGR
   };
-  static final int[] FORMATS_4BYTE = {
+  static final int[] FORMATS_4SAMPLE = {
     TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB, TJ.PF_CMYK
   };
   static final int[] FORMATS_4BYTEBI = {
@@ -92,7 +96,11 @@ final class TJUnitTest {
   };
 
   private static boolean doYUV = false;
-  private static int pad = 4;
+  private static boolean lossless = false;
+  private static int psv = 1;
+  private static int yuvAlign = 4;
+  private static int precision = 8;
+  private static int sampleSize, maxSample, tolerance, redToY, yellowToY;
   private static boolean bi = false;
 
   private static int exitStatus = 0;
@@ -142,8 +150,22 @@ final class TJUnitTest {
     }
   }
 
-  static void initBuf(byte[] buf, int w, int pitch, int h, int pf, int flags)
-                      throws Exception {
+  static void fillArray(Object buf, int val) {
+    if (precision == 8)
+      Arrays.fill((byte[])buf, (byte)val);
+    else
+      Arrays.fill((short[])buf, (short)val);
+  }
+
+  static void setVal(Object buf, int index, int value) {
+    if (precision == 8)
+      ((byte[])buf)[index] = (byte)value;
+    else
+      ((short[])buf)[index] = (short)value;
+  }
+
+  static void initBuf(Object buf, int w, int pitch, int h, int pf,
+                      boolean bottomUp) throws Exception {
     int roffset = TJ.getRedOffset(pf);
     int goffset = TJ.getGreenOffset(pf);
     int boffset = TJ.getBlueOffset(pf);
@@ -152,67 +174,67 @@ final class TJUnitTest {
     int index, row, col, halfway = 16;
 
     if (pf == TJ.PF_GRAY) {
-      Arrays.fill(buf, (byte)0);
+      fillArray(buf, 0);
       for (row = 0; row < h; row++) {
         for (col = 0; col < w; col++) {
-          if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+          if (bottomUp)
             index = pitch * (h - row - 1) + col;
           else
             index = pitch * row + col;
           if (((row / 8) + (col / 8)) % 2 == 0)
-            buf[index] = (row < halfway) ? (byte)255 : 0;
+            setVal(buf, index, (row < halfway) ? maxSample : 0);
           else
-            buf[index] = (row < halfway) ? 76 : (byte)226;
+            setVal(buf, index, (row < halfway) ? redToY : yellowToY);
         }
       }
       return;
     }
     if (pf == TJ.PF_CMYK) {
-      Arrays.fill(buf, (byte)255);
+      fillArray(buf, maxSample);
       for (row = 0; row < h; row++) {
         for (col = 0; col < w; col++) {
-          if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+          if (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;
+            if (row >= halfway) setVal(buf, index * ps + 3, 0);
           } else {
-            buf[index * ps + 2] = 0;
+            setVal(buf, index * ps + 2, 0);
             if (row < halfway)
-              buf[index * ps + 1] = 0;
+              setVal(buf, index * ps + 1, 0);
           }
         }
       }
       return;
     }
 
-    Arrays.fill(buf, (byte)0);
+    fillArray(buf, 0);
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
-        if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+        if (bottomUp)
           index = pitch * (h - row - 1) + col * ps;
         else
           index = pitch * row + col * ps;
         if (((row / 8) + (col / 8)) % 2 == 0) {
           if (row < halfway) {
-            buf[index + roffset] = (byte)255;
-            buf[index + goffset] = (byte)255;
-            buf[index + boffset] = (byte)255;
+            setVal(buf, index + roffset, maxSample);
+            setVal(buf, index + goffset, maxSample);
+            setVal(buf, index + boffset, maxSample);
           }
         } else {
-          buf[index + roffset] = (byte)255;
+          setVal(buf, index + roffset, maxSample);
           if (row >= halfway)
-            buf[index + goffset] = (byte)255;
+            setVal(buf, index + goffset, maxSample);
         }
         if (aoffset >= 0)
-          buf[index + aoffset] = (byte)255;
+          setVal(buf, index + aoffset, maxSample);
       }
     }
   }
 
-  static void initIntBuf(int[] buf, int w, int pitch, int h, int pf, int flags)
-                         throws Exception {
+  static void initIntBuf(int[] buf, int w, int pitch, int h, int pf,
+                         boolean bottomUp) throws Exception {
     int rshift = TJ.getRedOffset(pf) * 8;
     int gshift = TJ.getGreenOffset(pf) * 8;
     int bshift = TJ.getBlueOffset(pf) * 8;
@@ -222,7 +244,7 @@ final class TJUnitTest {
     Arrays.fill(buf, 0);
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
-        if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+        if (bottomUp)
           index = pitch * (h - row - 1) + col;
         else
           index = pitch * row + col;
@@ -243,7 +265,8 @@ final class TJUnitTest {
     }
   }
 
-  static void initImg(BufferedImage img, int pf, int flags) throws Exception {
+  static void initImg(BufferedImage img, int pf, boolean bottomUp)
+                      throws Exception {
     WritableRaster wr = img.getRaster();
     int imgType = img.getType();
 
@@ -256,20 +279,20 @@ final class TJUnitTest {
       int pitch = sm.getScanlineStride();
       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
       int[] buf = db.getData();
-      initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
+      initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, bottomUp);
     } else {
       ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
       int pitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       byte[] buf = db.getData();
-      initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
+      initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, bottomUp);
     }
   }
 
   static void checkVal(int row, int col, int v, String vname, int cv)
                        throws Exception {
     v = (v < 0) ? v + 256 : v;
-    if (v < cv - 1 || v > cv + 1) {
+    if (v < cv - tolerance || v > cv + tolerance) {
       throw new Exception("Comp. " + vname + " at " + row + "," + col +
                           " should be " + cv + ", not " + v);
     }
@@ -278,23 +301,34 @@ final class TJUnitTest {
   static void checkVal0(int row, int col, int v, String vname)
                         throws Exception {
     v = (v < 0) ? v + 256 : v;
-    if (v > 1) {
+    if (v > tolerance) {
       throw new Exception("Comp. " + vname + " at " + row + "," + col +
                           " should be 0, not " + v);
     }
   }
 
-  static void checkVal255(int row, int col, int v, String vname)
+  static void checkValMax(int row, int col, int v, String vname)
                           throws Exception {
     v = (v < 0) ? v + 256 : v;
-    if (v < 254) {
+    if (v < maxSample - tolerance) {
       throw new Exception("Comp. " + vname + " at " + row + "," + col +
-                          " should be 255, not " + v);
+                          " should be " + maxSample + ", not " + v);
     }
   }
 
-  static int checkBuf(byte[] buf, int w, int pitch, int h, int pf, int subsamp,
-                      TJScalingFactor sf, int flags) throws Exception {
+  static int getVal(Object buf, int index) {
+    int v;
+    if (precision == 8)
+      v = (int)(((byte[])buf)[index]);
+    else
+      v = (int)(((short[])buf)[index]);
+    if (v < 0)
+      v += maxSample + 1;
+    return v;
+  }
+
+  static int checkBuf(Object buf, int w, int pitch, int h, int pf, int subsamp,
+                      TJScalingFactor sf, boolean bottomUp) throws Exception {
     int roffset = TJ.getRedOffset(pf);
     int goffset = TJ.getGreenOffset(pf);
     int boffset = TJ.getBlueOffset(pf);
@@ -312,29 +346,29 @@ final class TJUnitTest {
       if (pf == TJ.PF_CMYK) {
         for (row = 0; row < h; row++) {
           for (col = 0; col < w; col++) {
-            if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+            if (bottomUp)
               index = (h - row - 1) * w + col;
             else
               index = row * w + col;
-            byte c = buf[index * ps];
-            byte m = buf[index * ps + 1];
-            byte y = buf[index * ps + 2];
-            byte k = buf[index * ps + 3];
-            checkVal255(row, col, c, "C");
+            int c = getVal(buf, index * ps);
+            int m = getVal(buf, index * ps + 1);
+            int y = getVal(buf, index * ps + 2);
+            int k = getVal(buf, index * ps + 3);
+            checkValMax(row, col, c, "C");
             if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
-              checkVal255(row, col, m, "M");
-              checkVal255(row, col, y, "Y");
+              checkValMax(row, col, m, "M");
+              checkValMax(row, col, y, "Y");
               if (row < halfway)
-                checkVal255(row, col, k, "K");
+                checkValMax(row, col, k, "K");
               else
                 checkVal0(row, col, k, "K");
             } else {
               checkVal0(row, col, y, "Y");
-              checkVal255(row, col, k, "K");
+              checkValMax(row, col, k, "K");
               if (row < halfway)
                 checkVal0(row, col, m, "M");
               else
-                checkVal255(row, col, m, "M");
+                checkValMax(row, col, m, "M");
             }
           }
         }
@@ -343,19 +377,19 @@ final class TJUnitTest {
 
       for (row = 0; row < halfway; row++) {
         for (col = 0; col < w; col++) {
-          if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+          if (bottomUp)
             index = pitch * (h - row - 1) + col * ps;
           else
             index = pitch * row + col * ps;
-          byte r = buf[index + roffset];
-          byte g = buf[index + goffset];
-          byte b = buf[index + boffset];
-          byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255;
+          int r = getVal(buf, index + roffset);
+          int g = getVal(buf, index + goffset);
+          int b = getVal(buf, index + boffset);
+          int a = aoffset >= 0 ? getVal(buf, index + aoffset) : maxSample;
           if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
             if (row < halfway) {
-              checkVal255(row, col, r, "R");
-              checkVal255(row, col, g, "G");
-              checkVal255(row, col, b, "B");
+              checkValMax(row, col, r, "R");
+              checkValMax(row, col, g, "G");
+              checkValMax(row, col, b, "B");
             } else {
               checkVal0(row, col, r, "R");
               checkVal0(row, col, g, "G");
@@ -364,25 +398,25 @@ final class TJUnitTest {
           } else {
             if (subsamp == TJ.SAMP_GRAY) {
               if (row < halfway) {
-                checkVal(row, col, r, "R", 76);
-                checkVal(row, col, g, "G", 76);
-                checkVal(row, col, b, "B", 76);
+                checkVal(row, col, r, "R", redToY);
+                checkVal(row, col, g, "G", redToY);
+                checkVal(row, col, b, "B", redToY);
               } else {
-                checkVal(row, col, r, "R", 226);
-                checkVal(row, col, g, "G", 226);
-                checkVal(row, col, b, "B", 226);
+                checkVal(row, col, r, "R", yellowToY);
+                checkVal(row, col, g, "G", yellowToY);
+                checkVal(row, col, b, "B", yellowToY);
               }
             } else {
-              checkVal255(row, col, r, "R");
+              checkValMax(row, col, r, "R");
               if (row < halfway) {
                 checkVal0(row, col, g, "G");
               } else {
-                checkVal255(row, col, g, "G");
+                checkValMax(row, col, g, "G");
               }
               checkVal0(row, col, b, "B");
             }
           }
-          checkVal255(row, col, a, "A");
+          checkValMax(row, col, a, "A");
         }
       }
     } catch (Exception e) {
@@ -394,22 +428,15 @@ final class TJUnitTest {
       for (row = 0; row < h; row++) {
         for (col = 0; col < w; col++) {
           if (pf == TJ.PF_CMYK) {
-            int c = buf[pitch * row + col * ps];
-            int m = buf[pitch * row + col * ps + 1];
-            int y = buf[pitch * row + col * ps + 2];
-            int k = buf[pitch * row + col * ps + 3];
-            if (c < 0) c += 256;
-            if (m < 0) m += 256;
-            if (y < 0) y += 256;
-            if (k < 0) k += 256;
+            int c = getVal(buf, pitch * row + col * ps);
+            int m = getVal(buf, pitch * row + col * ps + 1);
+            int y = getVal(buf, pitch * row + col * ps + 2);
+            int k = getVal(buf, pitch * row + col * ps + 3);
             System.out.format("%3d/%3d/%3d/%3d ", c, m, y, k);
           } else {
-            int r = buf[pitch * row + col * ps + roffset];
-            int g = buf[pitch * row + col * ps + goffset];
-            int b = buf[pitch * row + col * ps + boffset];
-            if (r < 0) r += 256;
-            if (g < 0) g += 256;
-            if (b < 0) b += 256;
+            int r = getVal(buf, pitch * row + col * ps + roffset);
+            int g = getVal(buf, pitch * row + col * ps + goffset);
+            int b = getVal(buf, pitch * row + col * ps + boffset);
             System.out.format("%3d/%3d/%3d ", r, g, b);
           }
         }
@@ -420,7 +447,7 @@ final class TJUnitTest {
   }
 
   static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
-                         int subsamp, TJScalingFactor sf, int flags)
+                         int subsamp, TJScalingFactor sf, boolean bottomUp)
                          throws Exception {
     int rshift = TJ.getRedOffset(pf) * 8;
     int gshift = TJ.getGreenOffset(pf) * 8;
@@ -433,7 +460,7 @@ final class TJUnitTest {
     try {
       for (row = 0; row < halfway; row++) {
         for (col = 0; col < w; col++) {
-          if ((flags & TJ.FLAG_BOTTOMUP) != 0)
+          if (bottomUp)
             index = pitch * (h - row - 1) + col;
           else
             index = pitch * row + col;
@@ -443,9 +470,9 @@ final class TJUnitTest {
           int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255;
           if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
             if (row < halfway) {
-              checkVal255(row, col, r, "R");
-              checkVal255(row, col, g, "G");
-              checkVal255(row, col, b, "B");
+              checkValMax(row, col, r, "R");
+              checkValMax(row, col, g, "G");
+              checkValMax(row, col, b, "B");
             } else {
               checkVal0(row, col, r, "R");
               checkVal0(row, col, g, "G");
@@ -463,16 +490,16 @@ final class TJUnitTest {
                 checkVal(row, col, b, "B", 226);
               }
             } else {
-              checkVal255(row, col, r, "R");
+              checkValMax(row, col, r, "R");
               if (row < halfway) {
                 checkVal0(row, col, g, "G");
               } else {
-                checkVal255(row, col, g, "G");
+                checkValMax(row, col, g, "G");
               }
               checkVal0(row, col, b, "B");
             }
           }
-          checkVal255(row, col, a, "A");
+          checkValMax(row, col, a, "A");
         }
       }
     } catch (Exception e) {
@@ -498,7 +525,7 @@ final class TJUnitTest {
   }
 
   static int checkImg(BufferedImage img, int pf, int subsamp,
-                      TJScalingFactor sf, int flags) throws Exception {
+                      TJScalingFactor sf, boolean bottomUp) throws Exception {
     WritableRaster wr = img.getRaster();
     int imgType = img.getType();
     if (imgType == BufferedImage.TYPE_INT_RGB ||
@@ -511,14 +538,14 @@ final class TJUnitTest {
       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
       int[] buf = db.getData();
       return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
-                         subsamp, sf, flags);
+                         subsamp, sf, bottomUp);
     } else {
       ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
       int pitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       byte[] buf = db.getData();
       return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
-                      sf, flags);
+                      sf, bottomUp);
     }
   }
 
@@ -532,7 +559,7 @@ final class TJUnitTest {
     int hsf = TJ.getMCUWidth(subsamp) / 8, vsf = TJ.getMCUHeight(subsamp) / 8;
     int pw = pad(w, hsf), ph = pad(h, vsf);
     int cw = pw / hsf, ch = ph / vsf;
-    int ypitch = pad(pw, pad), uvpitch = pad(cw, pad);
+    int ypitch = pad(pw, yuvAlign), uvpitch = pad(cw, yuvAlign);
     int retval = 1;
     int correctsize = ypitch * ph +
                       (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
@@ -549,7 +576,7 @@ final class TJUnitTest {
           byte y = buf[ypitch * row + col];
           if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
             if (row < halfway)
-              checkVal255(row, col, y, "Y");
+              checkValMax(row, col, y, "Y");
             else
               checkVal0(row, col, y, "Y");
           } else {
@@ -572,7 +599,7 @@ final class TJUnitTest {
             } else {
               if (row < halfway) {
                 checkVal(row, col, u, "U", 85);
-                checkVal255(row, col, v, "V");
+                checkValMax(row, col, v, "V");
               } else {
                 checkVal0(row, col, u, "U");
                 checkVal(row, col, v, "V", 149);
@@ -627,15 +654,17 @@ final class TJUnitTest {
   }
 
   static int compTest(TJCompressor tjc, byte[] dstBuf, int w, int h, int pf,
-                      String baseName, int subsamp, int jpegQual, int flags)
-                      throws Exception {
+                      String baseName) throws Exception {
     String tempStr;
-    byte[] srcBuf = null;
+    Object srcBuf = null;
     BufferedImage img = null;
     String pfStr, pfStrLong;
-    String buStr = (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD";
-    String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
-                       "Bottom-Up" : "Top-Down ";
+    boolean bottomUp = (tjc.get(TJ.PARAM_BOTTOMUP) == 1);
+    int subsamp = tjc.get(TJ.PARAM_SUBSAMP);
+    int jpegQual = tjc.get(TJ.PARAM_QUALITY);
+    int jpegPSV = tjc.get(TJ.PARAM_LOSSLESSPSV);
+    String buStr = bottomUp ? "BU" : "TD";
+    String buStrLong = bottomUp ? "Bottom-Up" : "Top-Down ";
     int size = 0, ps, imgType = pf;
 
     if (bi) {
@@ -650,25 +679,31 @@ final class TJUnitTest {
 
     if (bi) {
       img = new BufferedImage(w, h, imgType);
-      initImg(img, pf, flags);
-      tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
-                SUBNAME[subsamp] + "_Q" + jpegQual + ".png";
+      initImg(img, pf, bottomUp);
+      tempStr = baseName + "_enc" + precision + "_" + pfStr + "_" + buStr +
+                "_" + SUBNAME[subsamp] + "_Q" + jpegQual + ".png";
       File file = new File(tempStr);
       ImageIO.write(img, "png", file);
       tjc.setSourceImage(img, 0, 0, 0, 0);
     } else {
-      srcBuf = new byte[w * h * ps + 1];
-      initBuf(srcBuf, w, w * ps, h, pf, flags);
-      tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, pf);
+      if (precision == 8)
+        srcBuf = new byte[w * h * ps + 1];
+      else
+        srcBuf = new short[w * h * ps + 1];
+      initBuf(srcBuf, w, w * ps, h, pf, bottomUp);
+      if (precision == 8)
+        tjc.setSourceImage((byte[])srcBuf, 0, 0, w, 0, h, pf);
+      else if (precision == 12)
+        tjc.setSourceImage12((short[])srcBuf, 0, 0, w, 0, h, pf);
+      else
+        tjc.setSourceImage16((short[])srcBuf, 0, 0, w, 0, h, pf);
     }
     Arrays.fill(dstBuf, (byte)0);
 
-    tjc.setSubsamp(subsamp);
-    tjc.setJPEGQuality(jpegQual);
     if (doYUV) {
       System.out.format("%s %s -> YUV %s ... ", pfStrLong, buStrLong,
                         SUBNAME_LONG[subsamp]);
-      YUVImage yuvImage = tjc.encodeYUV(pad, flags);
+      YUVImage yuvImage = tjc.encodeYUV(yuvAlign);
       if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), w, h, subsamp,
                       new TJScalingFactor(1, 1)) == 1)
         System.out.print("Passed.\n");
@@ -681,14 +716,22 @@ final class TJUnitTest {
                         buStrLong, jpegQual);
       tjc.setSourceImage(yuvImage);
     } else {
-      System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong,
-                        SUBNAME_LONG[subsamp], jpegQual);
+      if (lossless)
+        System.out.format("%s %s -> LOSSLESS PSV%d ... ", pfStrLong, buStrLong,
+                          jpegPSV);
+      else
+        System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong,
+                          SUBNAME_LONG[subsamp], jpegQual);
     }
-    tjc.compress(dstBuf, flags);
+    tjc.compress(dstBuf);
     size = tjc.getCompressedSize();
 
-    tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
-              SUBNAME[subsamp] + "_Q" + jpegQual + ".jpg";
+    if (lossless)
+      tempStr = baseName + "_enc" + precision + "_" + pfStr + "_" + buStr +
+                "_LOSSLESS_PSV" + jpegPSV + ".jpg";
+    else
+      tempStr = baseName + "_enc" + precision + "_" + pfStr + "_" + buStr +
+                "_" + SUBNAME[subsamp] + "_Q" + jpegQual + ".jpg";
     writeJPEG(dstBuf, size, tempStr);
     System.out.println("Done.\n  Result in " + tempStr);
 
@@ -697,15 +740,15 @@ final class TJUnitTest {
 
   static void decompTest(TJDecompressor tjd, byte[] jpegBuf, int jpegSize,
                          int w, int h, int pf, String baseName, int subsamp,
-                         int flags, TJScalingFactor sf) throws Exception {
+                         TJScalingFactor sf) throws Exception {
     String pfStr, pfStrLong, tempStr;
-    String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
-                       "Bottom-Up" : "Top-Down ";
+    boolean bottomUp = (tjd.get(TJ.PARAM_BOTTOMUP) == 1);
+    String buStrLong = bottomUp ? "Bottom-Up" : "Top-Down ";
     int scaledWidth = sf.getScaled(w);
     int scaledHeight = sf.getScaled(h);
     int temp1, temp2, imgType = pf;
     BufferedImage img = null;
-    byte[] dstBuf = null;
+    Object dstBuf = null;
 
     if (bi) {
       pf = biTypePF(imgType);
@@ -717,24 +760,19 @@ final class TJUnitTest {
     }
 
     tjd.setSourceImage(jpegBuf, jpegSize);
+    tjd.setScalingFactor(sf);
+    if (lossless && subsamp != TJ.SAMP_444 && subsamp != TJ.SAMP_GRAY)
+      subsamp = TJ.SAMP_444;
     if (tjd.getWidth() != w || tjd.getHeight() != h ||
-        tjd.getSubsamp() != subsamp)
+        tjd.get(TJ.PARAM_SUBSAMP) != subsamp)
       throw new Exception("Incorrect JPEG header");
 
-    temp1 = scaledWidth;
-    temp2 = scaledHeight;
-    temp1 = tjd.getScaledWidth(temp1, temp2);
-    temp2 = tjd.getScaledHeight(temp1, temp2);
-    if (temp1 != scaledWidth || temp2 != scaledHeight)
-      throw new Exception("Scaled size mismatch");
-
     if (doYUV) {
       System.out.format("JPEG -> YUV %s ", SUBNAME_LONG[subsamp]);
       if (!sf.isOne())
         System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom());
       else System.out.print("... ");
-      YUVImage yuvImage = tjd.decompressToYUV(scaledWidth, pad, scaledHeight,
-                                              flags);
+      YUVImage yuvImage = tjd.decompressToYUV(yuvAlign);
       if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), scaledWidth,
                       scaledHeight, subsamp, sf) == 1)
         System.out.print("Passed.\n");
@@ -752,23 +790,28 @@ final class TJUnitTest {
       else System.out.print("... ");
     }
     if (bi)
-      img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags);
-    else
-      dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
+      img = tjd.decompress8(imgType);
+    else {
+      if (precision == 8)
+        dstBuf = tjd.decompress8(0, pf);
+      else if (precision == 12)
+        dstBuf = tjd.decompress12(0, pf);
+      else
+        dstBuf = tjd.decompress16(0, pf);
+    }
 
     if (bi) {
-      tempStr = baseName + "_dec_" + pfStr + "_" +
-                (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" +
-                SUBNAME[subsamp] + "_" +
+      tempStr = baseName + "_dec_" + pfStr + "_" + (bottomUp ? "BU" : "TD") +
+                "_" + SUBNAME[subsamp] + "_" +
                 (double)sf.getNum() / (double)sf.getDenom() + "x" + ".png";
       File file = new File(tempStr);
       ImageIO.write(img, "png", file);
     }
 
-    if ((bi && checkImg(img, pf, subsamp, sf, flags) == 1) ||
+    if ((bi && checkImg(img, pf, subsamp, sf, bottomUp) == 1) ||
         (!bi && checkBuf(dstBuf, scaledWidth,
                          scaledWidth * TJ.getPixelSize(pf), scaledHeight, pf,
-                         subsamp, sf, flags) == 1))
+                         subsamp, sf, bottomUp) == 1))
       System.out.print("Passed.\n");
     else {
       System.out.print("FAILED!\n");
@@ -777,20 +820,26 @@ final class TJUnitTest {
   }
 
   static void decompTest(TJDecompressor tjd, byte[] jpegBuf, int jpegSize,
-                         int w, int h, int pf, String baseName, int subsamp,
-                         int flags) throws Exception {
+                         int w, int h, int pf, String baseName, int subsamp)
+                         throws Exception {
     int i;
+
+    if (lossless) {
+      decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
+                 TJ.UNSCALED);
+      return;
+    }
+
     TJScalingFactor[] sf = TJ.getScalingFactors();
     for (i = 0; i < sf.length; i++) {
       int num = sf[i].getNum();
       int denom = sf[i].getDenom();
       if (subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY ||
-          (subsamp == TJ.SAMP_411 && num == 1 &&
+          ((subsamp == TJ.SAMP_411 || subsamp == TJ.SAMP_441) && num == 1 &&
            (denom == 2 || denom == 1)) ||
-          (subsamp != TJ.SAMP_411 && num == 1 &&
+          (subsamp != TJ.SAMP_411 && subsamp != TJ.SAMP_441 && num == 1 &&
            (denom == 4 || denom == 2 || denom == 1)))
-        decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
-                   flags, sf[i]);
+        decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp, sf[i]);
     }
   }
 
@@ -801,28 +850,38 @@ final class TJUnitTest {
     int size;
     byte[] dstBuf;
 
+    if (lossless && subsamp != TJ.SAMP_GRAY)
+      subsamp = TJ.SAMP_444;
+
     dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
 
     try {
       tjc = new TJCompressor();
       tjd = new TJDecompressor();
 
+      if (lossless) {
+        tjc.set(TJ.PARAM_LOSSLESS, 1);
+        tjc.set(TJ.PARAM_LOSSLESSPSV, ((psv++ - 1) % 7) + 1);
+      } else {
+        tjc.set(TJ.PARAM_QUALITY, 100);
+        if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 ||
+            subsamp == TJ.SAMP_440 || subsamp == TJ.SAMP_411 ||
+            subsamp == TJ.SAMP_441)
+          tjd.set(TJ.PARAM_FASTUPSAMPLE, 1);
+      }
+      tjc.set(TJ.PARAM_SUBSAMP, subsamp);
+
       for (int pf : formats) {
         if (pf < 0) continue;
         for (int i = 0; i < 2; i++) {
-          int flags = 0;
-          if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 ||
-              subsamp == TJ.SAMP_440 || subsamp == TJ.SAMP_411)
-            flags |= TJ.FLAG_FASTUPSAMPLE;
-          if (i == 1)
-            flags |= TJ.FLAG_BOTTOMUP;
-          size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100,
-                          flags);
-          decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags);
+          tjc.set(TJ.PARAM_BOTTOMUP, i == 1 ? 1 : 0);
+          tjd.set(TJ.PARAM_BOTTOMUP, i == 1 ? 1 : 0);
+          size = compTest(tjc, dstBuf, w, h, pf, baseName);
+          decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp);
           if (pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi) {
             System.out.print("\n");
             decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX),
-                       baseName, subsamp, flags);
+                       baseName, subsamp);
           }
           System.out.print("\n");
         }
@@ -837,8 +896,57 @@ final class TJUnitTest {
     if (tjd != null) tjd.close();
   }
 
+  static void overflowTest() throws Exception {
+    /* Ensure that the various buffer size methods don't overflow */
+    int size = 0;
+    boolean exception = false;
+
+    try {
+      exception = false;
+      size = TJ.bufSize(18919, 18919, TJ.SAMP_444);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.bufSize() overflow");
+    try {
+      exception = false;
+      size = TJ.bufSizeYUV(26755, 1, 26755, TJ.SAMP_444);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.bufSizeYUV() overflow");
+    try {
+      exception = false;
+      size = TJ.bufSizeYUV(26754, 3, 26754, TJ.SAMP_444);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.bufSizeYUV() overflow");
+    try {
+      exception = false;
+      size = TJ.bufSizeYUV(26754, -1, 26754, TJ.SAMP_444);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.bufSizeYUV() overflow");
+    try {
+      exception = false;
+      size = TJ.planeSizeYUV(0, 46341, 0, 46341, TJ.SAMP_444);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.planeSizeYUV() overflow");
+    try {
+      exception = false;
+      size = TJ.planeWidth(0, Integer.MAX_VALUE, TJ.SAMP_420);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.planeWidth() overflow");
+    try {
+      exception = false;
+      size = TJ.planeHeight(0, Integer.MAX_VALUE, TJ.SAMP_420);
+    } catch (Exception e) { exception = true; }
+    if (!exception || size != 0)
+      throw new Exception("TJ.planeHeight() overflow");
+  }
+
   static void bufSizeTest() throws Exception {
-    int w, h, i, subsamp;
+    int w, h, i, subsamp, numSamp = TJ.NUMSAMP;
     byte[] srcBuf, dstBuf = null;
     YUVImage dstImage = null;
     TJCompressor tjc = null;
@@ -846,8 +954,17 @@ final class TJUnitTest {
 
     try {
       tjc = new TJCompressor();
+
+      if (lossless) {
+        tjc.set(TJ.PARAM_LOSSLESS, 1);
+        tjc.set(TJ.PARAM_LOSSLESSPSV, ((psv++ - 1) % 7) + 1);
+        numSamp = 1;
+      } else
+        tjc.set(TJ.PARAM_QUALITY, 100);
+
       System.out.println("Buffer size regression test");
-      for (subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) {
+      for (subsamp = 0; subsamp < numSamp; subsamp++) {
+        tjc.set(TJ.PARAM_SUBSAMP, subsamp);
         for (w = 1; w < 48; w++) {
           int maxh = (w == 1) ? 2048 : 48;
           for (h = 1; h < maxh; h++) {
@@ -855,23 +972,21 @@ final class TJUnitTest {
               System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
             srcBuf = new byte[w * h * 4];
             if (doYUV)
-              dstImage = new YUVImage(w, pad, h, subsamp);
+              dstImage = new YUVImage(w, yuvAlign, h, subsamp);
             else
               dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
             for (i = 0; i < w * h * 4; i++) {
               srcBuf[i] = (byte)(r.nextInt(2) * 255);
             }
             tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, TJ.PF_BGRX);
-            tjc.setSubsamp(subsamp);
-            tjc.setJPEGQuality(100);
             if (doYUV)
-              tjc.encodeYUV(dstImage, 0);
+              tjc.encodeYUV(dstImage);
             else
-              tjc.compress(dstBuf, 0);
+              tjc.compress(dstBuf);
 
             srcBuf = new byte[h * w * 4];
             if (doYUV)
-              dstImage = new YUVImage(h, pad, w, subsamp);
+              dstImage = new YUVImage(h, yuvAlign, w, subsamp);
             else
               dstBuf = new byte[TJ.bufSize(h, w, subsamp)];
             for (i = 0; i < h * w * 4; i++) {
@@ -879,9 +994,9 @@ final class TJUnitTest {
             }
             tjc.setSourceImage(srcBuf, 0, 0, h, 0, w, TJ.PF_BGRX);
             if (doYUV)
-              tjc.encodeYUV(dstImage, 0);
+              tjc.encodeYUV(dstImage);
             else
-              tjc.compress(dstBuf, 0);
+              tjc.compress(dstBuf);
           }
           dstImage = null;
           dstBuf = null;
@@ -903,42 +1018,79 @@ final class TJUnitTest {
         if (argv[i].equalsIgnoreCase("-yuv"))
           doYUV = true;
         else if (argv[i].equalsIgnoreCase("-noyuvpad"))
-          pad = 1;
+          yuvAlign = 1;
+        else if (argv[i].equalsIgnoreCase("-lossless"))
+          lossless = true;
         else if (argv[i].equalsIgnoreCase("-bi")) {
           bi = true;
           testName = "javabitest";
+        } else if (argv[i].equalsIgnoreCase("-precision") &&
+                   i < argv.length - 1) {
+          int tempi = -1;
+
+          try {
+            tempi = Integer.parseInt(argv[++i]);
+          } catch (NumberFormatException e) {}
+          if (tempi != 8 && tempi != 12 && tempi != 16)
+            usage();
+          precision = tempi;
+          if (precision == 16)
+            lossless = true;
         } else
           usage();
       }
+      if (lossless && doYUV)
+        throw new Exception("Lossless JPEG and YUV encoding/decoding are incompatible.");
+      if (precision != 8 && doYUV)
+        throw new Exception("YUV encoding/decoding requires 8-bit data precision.");
+      if (precision != 8 && bi)
+        throw new Exception("BufferedImage support requires 8-bit data precision.");
+
+      System.out.format("Testing %d-bit precision\n", precision);
+      sampleSize = (precision == 8 ? 1 : 2);
+      maxSample = (1 << precision) - 1;
+      tolerance = (lossless ? 0 : (precision > 8 ? 2 : 1));
+      redToY = (19595 * maxSample) >> 16;
+      yellowToY = (58065 * maxSample) >> 16;
+
       if (doYUV)
-        FORMATS_4BYTE[4] = -1;
-      doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_444,
-             testName);
-      doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_444,
-             testName);
-      doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_422,
-             testName);
-      doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_422,
-             testName);
-      doTest(39, 41, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_420,
+        FORMATS_4SAMPLE[4] = -1;
+      overflowTest();
+      doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_444,
              testName);
-      doTest(41, 35, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_420,
+      doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_444,
              testName);
-      doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_440,
-             testName);
-      doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_440,
-             testName);
-      doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_411,
-             testName);
-      doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_411,
+      doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_422,
              testName);
+      if (!lossless) {
+        doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_422,
+               testName);
+        doTest(39, 41, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_420,
+               testName);
+        doTest(41, 35, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_420,
+               testName);
+        doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_440,
+               testName);
+        doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_440,
+               testName);
+        doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_411,
+               testName);
+        doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_411,
+               testName);
+        doTest(39, 41, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_441,
+               testName);
+        doTest(41, 35, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_441,
+               testName);
+      }
       doTest(39, 41, bi ? FORMATS_GRAYBI : FORMATS_GRAY, TJ.SAMP_GRAY,
              testName);
-      doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_GRAY,
-             testName);
-      FORMATS_4BYTE[4] = -1;
-      doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_GRAY,
-             testName);
+      if (!lossless) {
+        doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3SAMPLE, TJ.SAMP_GRAY,
+               testName);
+        FORMATS_4SAMPLE[4] = -1;
+        doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4SAMPLE, TJ.SAMP_GRAY,
+               testName);
+      }
       if (!bi)
         bufSizeTest();
       if (doYUV && !bi) {
@@ -948,6 +1100,7 @@ final class TJUnitTest {
         doTest(48, 48, FORMATS_RGB, TJ.SAMP_420, "javatest_yuv0");
         doTest(48, 48, FORMATS_RGB, TJ.SAMP_440, "javatest_yuv0");
         doTest(48, 48, FORMATS_RGB, TJ.SAMP_411, "javatest_yuv0");
+        doTest(48, 48, FORMATS_RGB, TJ.SAMP_441, "javatest_yuv0");
         doTest(48, 48, FORMATS_RGB, TJ.SAMP_GRAY, "javatest_yuv0");
         doTest(48, 48, FORMATS_GRAY, TJ.SAMP_GRAY, "javatest_yuv0");
       }
diff --git a/java/doc/allclasses-frame.html b/java/doc/allclasses-frame.html
deleted file mode 100644 (file)
index fecac06..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!-- NewPage -->
-<html lang="en">
-<head>
-<title>All Classes</title>
-<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
-</head>
-<body>
-<h1 class="bar">All Classes</h1>
-<div class="indexContainer">
-<ul>
-<li><a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJ</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJCompressor</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg" target="classFrame"><i>TJCustomFilter</i></a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJDecompressor</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJException</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJScalingFactor</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJTransform</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJTransformer</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">YUVImage</a></li>
-</ul>
-</div>
-</body>
-</html>
diff --git a/java/doc/allclasses-index.html b/java/doc/allclasses-index.html
new file mode 100644 (file)
index 0000000..f3179c5
--- /dev/null
@@ -0,0 +1,215 @@
+<!DOCTYPE HTML>
+<!-- NewPage -->
+<html lang="en">
+<head>
+<!-- Generated by javadoc -->
+<title>All Classes</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
+</head>
+<body>
+<script type="text/javascript"><!--
+    try {
+        if (location.href.indexOf('is-external=true') == -1) {
+            parent.document.title="All Classes";
+        }
+    }
+    catch(err) {
+    }
+//-->
+var data = {"i0":2,"i1":2,"i2":1,"i3":2,"i4":8,"i5":2,"i6":2,"i7":2,"i8":2};
+var tabs = {65535:["t0","All Classes"],1:["t1","Interface Summary"],2:["t2","Class Summary"],8:["t4","Exception Summary"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
+<!-- ========= START OF TOP NAVBAR ======= -->
+<div class="topNav"><a id="navbar.top">
+<!--   -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Class</li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList" id="allclasses_navbar_top">
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+  allClassesLink = document.getElementById("allclasses_navbar_top");
+  if(window==top) {
+    allClassesLink.style.display = "block";
+  }
+  else {
+    allClassesLink.style.display = "none";
+  }
+  //-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+</div>
+<a id="skip.navbar.top">
+<!--   -->
+</a></div>
+<!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
+<div class="header">
+<h1 title="All&amp;nbsp;Classes" class="title">All&nbsp;Classes</h1>
+</div>
+<div class="allClassesContainer">
+<ul class="blockList">
+<li class="blockList">
+<table class="typeSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Classes</span><span class="tabEnd">&nbsp;</span></span><span id="t1" class="tableTab"><span><a href="javascript:show(1);">Interface Summary</a></span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Class Summary</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Exception Summary</a></span><span class="tabEnd">&nbsp;</span></span></caption>
+<tr>
+<th class="colFirst" scope="col">Class</th>
+<th class="colLast" scope="col">Description</th>
+</tr>
+<tr id="i0" class="altColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></td>
+<th class="colLast" scope="row">
+<div class="block">TurboJPEG utility class (cannot be instantiated)</div>
+</th>
+</tr>
+<tr id="i1" class="rowColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></td>
+<th class="colLast" scope="row">
+<div class="block">TurboJPEG compressor</div>
+</th>
+</tr>
+<tr id="i2" class="altColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></td>
+<th class="colLast" scope="row">
+<div class="block">Custom filter callback interface</div>
+</th>
+</tr>
+<tr id="i3" class="rowColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></td>
+<th class="colLast" scope="row">
+<div class="block">TurboJPEG decompressor</div>
+</th>
+</tr>
+<tr id="i4" class="altColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></td>
+<th class="colLast" scope="row">&nbsp;</th>
+</tr>
+<tr id="i5" class="rowColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></td>
+<th class="colLast" scope="row">
+<div class="block">Fractional scaling factor</div>
+</th>
+</tr>
+<tr id="i6" class="altColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></td>
+<th class="colLast" scope="row">
+<div class="block">Lossless transform parameters</div>
+</th>
+</tr>
+<tr id="i7" class="rowColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></td>
+<th class="colLast" scope="row">
+<div class="block">TurboJPEG lossless transformer</div>
+</th>
+</tr>
+<tr id="i8" class="altColor">
+<td class="colFirst"><a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></td>
+<th class="colLast" scope="row">
+<div class="block">This class encapsulates a planar YUV image and the metadata
+ associated with it.</div>
+</th>
+</tr>
+</table>
+</li>
+</ul>
+</div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<div class="bottomNav"><a id="navbar.bottom">
+<!--   -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Class</li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList" id="allclasses_navbar_bottom">
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+  allClassesLink = document.getElementById("allclasses_navbar_bottom");
+  if(window==top) {
+    allClassesLink.style.display = "block";
+  }
+  else {
+    allClassesLink.style.display = "none";
+  }
+  //-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+</div>
+<a id="skip.navbar.bottom">
+<!--   -->
+</a></div>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
+</body>
+</html>
similarity index 57%
rename from java/doc/allclasses-noframe.html
rename to java/doc/allclasses.html
index 1f7fd3c..c87c92f 100644 (file)
@@ -1,17 +1,30 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>All Classes</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
-<h1 class="bar">All Classes</h1>
+<main role="main">
+<h1 class="bar">All&nbsp;Classes</h1>
 <div class="indexContainer">
 <ul>
 <li><a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></li>
 <li><a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></li>
-<li><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><i>TJCustomFilter</i></a></li>
+<li><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="interfaceName">TJCustomFilter</span></a></li>
 <li><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></li>
 <li><a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></li>
 <li><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></li>
@@ -20,5 +33,6 @@
 <li><a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></li>
 </ul>
 </div>
+</main>
 </body>
 </html>
diff --git a/java/doc/allpackages-index.html b/java/doc/allpackages-index.html
new file mode 100644 (file)
index 0000000..8ad354d
--- /dev/null
@@ -0,0 +1,162 @@
+<!DOCTYPE HTML>
+<!-- NewPage -->
+<html lang="en">
+<head>
+<!-- Generated by javadoc -->
+<title>All Packages</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
+</head>
+<body>
+<script type="text/javascript"><!--
+    try {
+        if (location.href.indexOf('is-external=true') == -1) {
+            parent.document.title="All Packages";
+        }
+    }
+    catch(err) {
+    }
+//-->
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
+<!-- ========= START OF TOP NAVBAR ======= -->
+<div class="topNav"><a id="navbar.top">
+<!--   -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Class</li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList" id="allclasses_navbar_top">
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+  allClassesLink = document.getElementById("allclasses_navbar_top");
+  if(window==top) {
+    allClassesLink.style.display = "block";
+  }
+  else {
+    allClassesLink.style.display = "none";
+  }
+  //-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+</div>
+<a id="skip.navbar.top">
+<!--   -->
+</a></div>
+<!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
+<div class="header">
+<h1 title="All&amp;nbsp;Packages" class="title">All&nbsp;Packages</h1>
+</div>
+<div class="allPackagesContainer">
+<ul class="blockList">
+<li class="blockList">
+<table class="packagesSummary">
+<caption><span>Package Summary</span><span class="tabEnd">&nbsp;</span></caption>
+<tr>
+<th class="colFirst" scope="col">Package</th>
+<th class="colLast" scope="col">Description</th>
+</tr>
+<tbody>
+<tr class="altColor">
+<th class="colFirst" scope="row"><a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></th>
+<td class="colLast">&nbsp;</td>
+</tr>
+</tbody>
+</table>
+</li>
+</ul>
+</div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<div class="bottomNav"><a id="navbar.bottom">
+<!--   -->
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Class</li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
+<li><a href="index-all.html">Index</a></li>
+<li><a href="help-doc.html">Help</a></li>
+</ul>
+</div>
+<div class="subNav">
+<ul class="navList" id="allclasses_navbar_bottom">
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<div>
+<script type="text/javascript"><!--
+  allClassesLink = document.getElementById("allclasses_navbar_bottom");
+  if(window==top) {
+    allClassesLink.style.display = "block";
+  }
+  else {
+    allClassesLink.style.display = "none";
+  }
+  //-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+</div>
+<a id="skip.navbar.bottom">
+<!--   -->
+</a></div>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
+</body>
+</html>
index 07ba052..1fa1fce 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Constant Field Values</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?constant-values.html" target="_top">Frames</a></li>
-<li><a href="constant-values.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 title="Constant Field Values" class="title">Constant Field Values</h1>
+<section>
 <h2 title="Contents">Contents</h2>
 <ul>
 <li><a href="#org.libjpegturbo">org.libjpegturbo.*</a></li>
 </ul>
+</section>
 </div>
-<div class="constantValuesContainer"><a name="org.libjpegturbo">
+<div class="constantValuesContainer"><a id="org.libjpegturbo">
 <!--   -->
 </a>
+<section>
 <h2 title="org.libjpegturbo">org.libjpegturbo.*</h2>
 <ul class="blockList">
 <li class="blockList">
-<table border="0" cellpadding="3" cellspacing="0" summary="Constant Field Values table, listing constant fields, and values">
+<table class="constantsSummary">
 <caption><span>org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th scope="col">Constant Field</th>
+<th class="colSecond" scope="col">Constant Field</th>
 <th class="colLast" scope="col">Value</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.CS_CMYK">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.CS_CMYK">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_CMYK">CS_CMYK</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_CMYK">CS_CMYK</a></code></th>
 <td class="colLast"><code>3</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.CS_GRAY">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.CS_GRAY">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_GRAY">CS_GRAY</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_GRAY">CS_GRAY</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.CS_RGB">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.CS_RGB">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_RGB">CS_RGB</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_RGB">CS_RGB</a></code></th>
 <td class="colLast"><code>0</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.CS_YCbCr">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.CS_YCbCr">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr">CS_YCbCr</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr">CS_YCbCr</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.CS_YCCK">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.CS_YCCK">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK">CS_YCCK</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK">CS_YCCK</a></code></th>
 <td class="colLast"><code>4</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.ERR_FATAL">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.ERR_FATAL">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_FATAL">ERR_FATAL</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_FATAL">ERR_FATAL</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.ERR_WARNING">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.ERR_WARNING">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_WARNING">ERR_WARNING</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_WARNING">ERR_WARNING</a></code></th>
 <td class="colLast"><code>0</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_ACCURATEDCT">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_ACCURATEDCT">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></code></th>
 <td class="colLast"><code>4096</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_BOTTOMUP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_BOTTOMUP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FASTDCT">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_FASTDCT">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">FLAG_FASTDCT</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">FLAG_FASTDCT</a></code></th>
 <td class="colLast"><code>2048</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FASTUPSAMPLE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_FASTUPSAMPLE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></code></th>
 <td class="colLast"><code>256</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FORCEMMX">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_LIMITSCANS">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCEMMX">FLAG_FORCEMMX</a></code></td>
-<td class="colLast"><code>8</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></code></th>
+<td class="colLast"><code>32768</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_PROGRESSIVE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE">FLAG_FORCESSE</a></code></td>
-<td class="colLast"><code>16</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></code></th>
+<td class="colLast"><code>16384</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE2">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.FLAG_STOPONWARNING">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE2">FLAG_FORCESSE2</a></code></td>
-<td class="colLast"><code>32</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></code></th>
+<td class="colLast"><code>8192</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE3">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.NUMCS">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE3">FLAG_FORCESSE3</a></code></td>
-<td class="colLast"><code>128</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMCS">NUMCS</a></code></th>
+<td class="colLast"><code>5</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_LIMITSCANS">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.NUMERR">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></code></td>
-<td class="colLast"><code>32768</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMERR">NUMERR</a></code></th>
+<td class="colLast"><code>2</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_PROGRESSIVE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.NUMPF">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></code></td>
-<td class="colLast"><code>16384</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMPF">NUMPF</a></code></th>
+<td class="colLast"><code>12</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.FLAG_STOPONWARNING">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.NUMSAMP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></code></td>
-<td class="colLast"><code>8192</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMSAMP">NUMSAMP</a></code></th>
+<td class="colLast"><code>7</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_ARITHMETIC">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_ARITHMETIC">PARAM_ARITHMETIC</a></code></th>
+<td class="colLast"><code>14</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_BOTTOMUP">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_BOTTOMUP">PARAM_BOTTOMUP</a></code></th>
+<td class="colLast"><code>1</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.NUMCS">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_COLORSPACE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMCS">NUMCS</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_COLORSPACE">PARAM_COLORSPACE</a></code></th>
+<td class="colLast"><code>8</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_DENSITYUNITS">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_DENSITYUNITS">PARAM_DENSITYUNITS</a></code></th>
+<td class="colLast"><code>22</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_FASTDCT">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT">PARAM_FASTDCT</a></code></th>
+<td class="colLast"><code>10</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_FASTUPSAMPLE">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTUPSAMPLE">PARAM_FASTUPSAMPLE</a></code></th>
+<td class="colLast"><code>9</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_JPEGHEIGHT">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_JPEGHEIGHT">PARAM_JPEGHEIGHT</a></code></th>
+<td class="colLast"><code>6</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_JPEGWIDTH">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_JPEGWIDTH">PARAM_JPEGWIDTH</a></code></th>
 <td class="colLast"><code>5</code></td>
 </tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESS">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESS">PARAM_LOSSLESS</a></code></th>
+<td class="colLast"><code>15</code></td>
+</tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.NUMERR">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESSPSV">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMERR">NUMERR</a></code></td>
-<td class="colLast"><code>2</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESSPSV">PARAM_LOSSLESSPSV</a></code></th>
+<td class="colLast"><code>16</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.NUMPF">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESSPT">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMPF">NUMPF</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESSPT">PARAM_LOSSLESSPT</a></code></th>
+<td class="colLast"><code>17</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_OPTIMIZE">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_OPTIMIZE">PARAM_OPTIMIZE</a></code></th>
+<td class="colLast"><code>11</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_PRECISION">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PRECISION">PARAM_PRECISION</a></code></th>
+<td class="colLast"><code>7</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_PROGRESSIVE">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PROGRESSIVE">PARAM_PROGRESSIVE</a></code></th>
 <td class="colLast"><code>12</code></td>
 </tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_QUALITY">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_QUALITY">PARAM_QUALITY</a></code></th>
+<td class="colLast"><code>3</code></td>
+</tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.NUMSAMP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_RESTARTBLOCKS">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMSAMP">NUMSAMP</a></code></td>
-<td class="colLast"><code>6</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_RESTARTBLOCKS">PARAM_RESTARTBLOCKS</a></code></th>
+<td class="colLast"><code>18</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_RESTARTROWS">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_RESTARTROWS">PARAM_RESTARTROWS</a></code></th>
+<td class="colLast"><code>19</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_SCANLIMIT">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SCANLIMIT">PARAM_SCANLIMIT</a></code></th>
+<td class="colLast"><code>13</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_STOPONWARNING">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_STOPONWARNING">PARAM_STOPONWARNING</a></code></th>
+<td class="colLast"><code>0</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_SUBSAMP">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP">PARAM_SUBSAMP</a></code></th>
+<td class="colLast"><code>4</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_XDENSITY">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_XDENSITY">PARAM_XDENSITY</a></code></th>
+<td class="colLast"><code>20</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PARAM_YDENSITY">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_YDENSITY">PARAM_YDENSITY</a></code></th>
+<td class="colLast"><code>21</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_ABGR">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_ABGR">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ABGR">PF_ABGR</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ABGR">PF_ABGR</a></code></th>
 <td class="colLast"><code>9</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_ARGB">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_ARGB">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ARGB">PF_ARGB</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ARGB">PF_ARGB</a></code></th>
 <td class="colLast"><code>10</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_BGR">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_BGR">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGR">PF_BGR</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGR">PF_BGR</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_BGRA">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_BGRA">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRA">PF_BGRA</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRA">PF_BGRA</a></code></th>
 <td class="colLast"><code>8</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_BGRX">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_BGRX">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX">PF_BGRX</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX">PF_BGRX</a></code></th>
 <td class="colLast"><code>3</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_CMYK">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_CMYK">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_CMYK">PF_CMYK</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_CMYK">PF_CMYK</a></code></th>
 <td class="colLast"><code>11</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_GRAY">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_GRAY">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_GRAY">PF_GRAY</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_GRAY">PF_GRAY</a></code></th>
 <td class="colLast"><code>6</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_RGB">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_RGB">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGB">PF_RGB</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGB">PF_RGB</a></code></th>
 <td class="colLast"><code>0</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_RGBA">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_RGBA">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBA">PF_RGBA</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBA">PF_RGBA</a></code></th>
 <td class="colLast"><code>7</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_RGBX">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_RGBX">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX">PF_RGBX</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX">PF_RGBX</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_XBGR">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_XBGR">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR">PF_XBGR</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR">PF_XBGR</a></code></th>
 <td class="colLast"><code>4</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.PF_XRGB">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.PF_XRGB">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB">PF_XRGB</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB">PF_XRGB</a></code></th>
 <td class="colLast"><code>5</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_411">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_411">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_411">SAMP_411</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_411">SAMP_411</a></code></th>
 <td class="colLast"><code>5</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_420">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_420">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_420">SAMP_420</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_420">SAMP_420</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_422">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_422">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_422">SAMP_422</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_422">SAMP_422</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_440">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_440">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_440">SAMP_440</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_440">SAMP_440</a></code></th>
 <td class="colLast"><code>4</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_444">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_441">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_444">SAMP_444</a></code></td>
-<td class="colLast"><code>0</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_441">SAMP_441</a></code></th>
+<td class="colLast"><code>6</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJ.SAMP_GRAY">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_444">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_444">SAMP_444</a></code></th>
+<td class="colLast"><code>0</code></td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_GRAY">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_GRAY">SAMP_GRAY</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_GRAY">SAMP_GRAY</a></code></th>
 <td class="colLast"><code>3</code></td>
 </tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJ.SAMP_UNKNOWN">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_UNKNOWN">SAMP_UNKNOWN</a></code></th>
+<td class="colLast"><code>-1</code></td>
+</tr>
 </tbody>
 </table>
 </li>
 <li class="blockList">
-<table border="0" cellpadding="3" cellspacing="0" summary="Constant Field Values table, listing constant fields, and values">
+<table class="constantsSummary">
 <caption><span>org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th scope="col">Constant Field</th>
+<th class="colSecond" scope="col">Constant Field</th>
 <th class="colLast" scope="col">Value</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.NUMOP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.NUMOP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#NUMOP">NUMOP</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#NUMOP">NUMOP</a></code></th>
 <td class="colLast"><code>8</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_HFLIP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_HFLIP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_HFLIP">OP_HFLIP</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_HFLIP">OP_HFLIP</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_NONE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_NONE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE">OP_NONE</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE">OP_NONE</a></code></th>
 <td class="colLast"><code>0</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT180">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT180">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT180">OP_ROT180</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT180">OP_ROT180</a></code></th>
 <td class="colLast"><code>6</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT270">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT270">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT270">OP_ROT270</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT270">OP_ROT270</a></code></th>
 <td class="colLast"><code>7</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT90">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_ROT90">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT90">OP_ROT90</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT90">OP_ROT90</a></code></th>
 <td class="colLast"><code>5</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSPOSE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSPOSE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSPOSE">OP_TRANSPOSE</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSPOSE">OP_TRANSPOSE</a></code></th>
 <td class="colLast"><code>3</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSVERSE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSVERSE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSVERSE">OP_TRANSVERSE</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSVERSE">OP_TRANSVERSE</a></code></th>
 <td class="colLast"><code>4</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OP_VFLIP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OP_VFLIP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_VFLIP">OP_VFLIP</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_VFLIP">OP_VFLIP</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_COPYNONE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_ARITHMETIC">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_COPYNONE">OPT_COPYNONE</a></code></td>
-<td class="colLast"><code>64</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_ARITHMETIC">OPT_ARITHMETIC</a></code></th>
+<td class="colLast"><code>128</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_CROP">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_COPYNONE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_CROP">OPT_CROP</a></code></td>
-<td class="colLast"><code>4</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_COPYNONE">OPT_COPYNONE</a></code></th>
+<td class="colLast"><code>64</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_GRAY">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_CROP">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_GRAY">OPT_GRAY</a></code></td>
-<td class="colLast"><code>8</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_CROP">OPT_CROP</a></code></th>
+<td class="colLast"><code>4</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_NOOUTPUT">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_GRAY">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_NOOUTPUT">OPT_NOOUTPUT</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_GRAY">OPT_GRAY</a></code></th>
+<td class="colLast"><code>8</code></td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_NOOUTPUT">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_NOOUTPUT">OPT_NOOUTPUT</a></code></th>
 <td class="colLast"><code>16</code></td>
 </tr>
+<tr class="altColor">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_OPTIMIZE">
+<!--   -->
+</a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_OPTIMIZE">OPT_OPTIMIZE</a></code></th>
+<td class="colLast"><code>256</code></td>
+</tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_PERFECT">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_PERFECT">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT">OPT_PERFECT</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT">OPT_PERFECT</a></code></th>
 <td class="colLast"><code>1</code></td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_PROGRESSIVE">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_PROGRESSIVE">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></code></th>
 <td class="colLast"><code>32</code></td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a name="org.libjpegturbo.turbojpeg.TJTransform.OPT_TRIM">
+<td class="colFirst"><a id="org.libjpegturbo.turbojpeg.TJTransform.OPT_TRIM">
 <!--   -->
 </a><code>public&nbsp;static&nbsp;final&nbsp;int</code></td>
-<td><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_TRIM">OPT_TRIM</a></code></td>
+<th class="colSecond" scope="row"><code><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_TRIM">OPT_TRIM</a></code></th>
 <td class="colLast"><code>2</code></td>
 </tr>
 </tbody>
 </table>
 </li>
 </ul>
+</section>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?constant-values.html" target="_top">Frames</a></li>
-<li><a href="constant-values.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 31d4e64..3f4f34a 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Deprecated List</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?deprecated-list.html" target="_top">Frames</a></li>
-<li><a href="deprecated-list.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 title="Deprecated API" class="title">Deprecated API</h1>
 <h2 title="Contents">Contents</h2>
 <ul>
-<li><a href="#field">Deprecated Fields</a></li>
-<li><a href="#method">Deprecated Methods</a></li>
-<li><a href="#constructor">Deprecated Constructors</a></li>
+<li><a href="#field">Fields</a></li>
+<li><a href="#method">Methods</a></li>
 </ul>
 </div>
-<div class="contentContainer"><a name="field">
+<div class="contentContainer"><a id="field">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<table border="0" cellpadding="3" cellspacing="0" summary="Deprecated Fields table, listing deprecated fields, and an explanation">
-<caption><span>Deprecated Fields</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="deprecatedSummary">
+<caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Field and Description</th>
+<th class="colFirst" scope="col">Field</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCEMMX">org.libjpegturbo.turbojpeg.TJ.FLAG_FORCEMMX</a></td>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">org.libjpegturbo.turbojpeg.TJ.FLAG_ACCURATEDCT</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT"><code>TJ.PARAM_FASTDCT</code></a> instead.</div>
+</td>
+</tr>
+<tr class="rowColor">
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">org.libjpegturbo.turbojpeg.TJ.FLAG_BOTTOMUP</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_BOTTOMUP"><code>TJ.PARAM_BOTTOMUP</code></a> instead.</div>
+</td>
+</tr>
+<tr class="altColor">
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">org.libjpegturbo.turbojpeg.TJ.FLAG_FASTDCT</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT"><code>TJ.PARAM_FASTDCT</code></a> instead.</div>
+</td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE">org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE</a></td>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">org.libjpegturbo.turbojpeg.TJ.FLAG_FASTUPSAMPLE</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTUPSAMPLE"><code>TJ.PARAM_FASTUPSAMPLE</code></a> instead.</div>
+</td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE2">org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE2</a></td>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">org.libjpegturbo.turbojpeg.TJ.FLAG_LIMITSCANS</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SCANLIMIT"><code>TJ.PARAM_SCANLIMIT</code></a> instead.</div>
+</td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE3">org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE3</a></td>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">org.libjpegturbo.turbojpeg.TJ.FLAG_PROGRESSIVE</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PROGRESSIVE"><code>TJ.PARAM_PROGRESSIVE</code></a> instead.</div>
+</td>
+</tr>
+<tr class="altColor">
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">org.libjpegturbo.turbojpeg.TJ.FLAG_STOPONWARNING</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> instead.</div>
+</td>
 </tr>
 </tbody>
 </table>
 </li>
 </ul>
-<a name="method">
+<a id="method">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<table border="0" cellpadding="3" cellspacing="0" summary="Deprecated Methods table, listing deprecated methods, and an explanation">
-<caption><span>Deprecated Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="deprecatedSummary">
+<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Method and Description</th>
+<th class="colFirst" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int)">org.libjpegturbo.turbojpeg.TJ.bufSizeYUV(int, int, int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>TJ.bufSizeYUV(int, int, int, int)</code></a> instead.</i></div>
-</td>
-</tr>
-<tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20byte[],%20int)">org.libjpegturbo.turbojpeg.TJCompressor.compress(BufferedImage, byte[], int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)"><code>TJCompressor.compress(byte[], int)</code></a> instead.</i></div>
-</td>
-</tr>
-<tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20int)">org.libjpegturbo.turbojpeg.TJCompressor.compress(BufferedImage, int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)"><code>TJCompressor.compress(int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte%5B%5D,int)">org.libjpegturbo.turbojpeg.TJCompressor.compress&#8203;(byte[], int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte%5B%5D)"><code>TJCompressor.compress(byte[])</code></a> instead.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int)">org.libjpegturbo.turbojpeg.TJDecompressor.decompress(byte[], int, int, int, int, int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJDecompressor.decompress(byte[], int, int, int, int, int, int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">org.libjpegturbo.turbojpeg.TJCompressor.encodeYUV&#8203;(YUVImage, int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>TJCompressor.encodeYUV(YUVImage)</code></a>
+ instead.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(byte[],%20int)">org.libjpegturbo.turbojpeg.TJDecompressor.decompressToYUV(byte[], int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>TJDecompressor.decompressToYUV(YUVImage, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setJPEGQuality(int)">org.libjpegturbo.turbojpeg.TJCompressor.setJPEGQuality&#8203;(int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use
+ <code><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_QUALITY"><code>TJ.PARAM_QUALITY</code></a>, ...)</code> instead.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)">org.libjpegturbo.turbojpeg.TJDecompressor.decompressToYUV(int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)"><code>TJDecompressor.decompressToYUV(int, int, int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSubsamp(int)">org.libjpegturbo.turbojpeg.TJCompressor.setSubsamp&#8203;(int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use
+ <code><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>, ...)</code> instead.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20byte[],%20int)">org.libjpegturbo.turbojpeg.TJCompressor.encodeYUV(BufferedImage, byte[], int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)"><code>TJCompressor.encodeYUV(byte[], int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte%5B%5D,int,int,int,int,int,int,int)">org.libjpegturbo.turbojpeg.TJDecompressor.decompress&#8203;(byte[], int, int, int, int, int, int, int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>,
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(byte%5B%5D,int,int,int,int)"><code>TJDecompressor.decompress8(byte[], int, int, int, int)</code></a> instead.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20int)">org.libjpegturbo.turbojpeg.TJCompressor.encodeYUV(BufferedImage, int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>TJCompressor.encodeYUV(int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">org.libjpegturbo.turbojpeg.TJDecompressor.decompressToYUV&#8203;(YUVImage, int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>TJDecompressor.decompressToYUV(YUVImage)</code></a> instead.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)">org.libjpegturbo.turbojpeg.TJCompressor.encodeYUV(byte[], int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>TJCompressor.encodeYUV(YUVImage, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getColorspace()">org.libjpegturbo.turbojpeg.TJDecompressor.getColorspace()</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <code><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#get(int)"><code>get</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_COLORSPACE"><code>TJ.PARAM_COLORSPACE</code></a>)</code>
+ instead.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int)">org.libjpegturbo.turbojpeg.TJCompressor.encodeYUV(int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>TJCompressor.encodeYUV(int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,int)">org.libjpegturbo.turbojpeg.TJDecompressor.getScaledHeight&#8203;(int, int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setJPEGImage(byte[],%20int)">org.libjpegturbo.turbojpeg.TJDecompressor.setJPEGImage(byte[], int)</a>
-<div class="block"><i>Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)"><code>TJDecompressor.setSourceImage(byte[], int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,int)">org.libjpegturbo.turbojpeg.TJDecompressor.getScaledWidth&#8203;(int, int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int)">org.libjpegturbo.turbojpeg.TJCompressor.setSourceImage(byte[], int, int, int, int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getSubsamp()">org.libjpegturbo.turbojpeg.TJDecompressor.getSubsamp()</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <code><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#get(int)"><code>get</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>)</code>
+ instead.</div>
 </td>
 </tr>
-</tbody>
-</table>
-</li>
-</ul>
-<a name="constructor">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<table border="0" cellpadding="3" cellspacing="0" summary="Deprecated Constructors table, listing deprecated constructors, and an explanation">
-<caption><span>Deprecated Constructors</span><span class="tabEnd">&nbsp;</span></caption>
-<tr>
-<th class="colOne" scope="col">Constructor and Description</th>
-</tr>
-<tbody>
 <tr class="altColor">
-<td class="colOne"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int)">org.libjpegturbo.turbojpeg.TJCompressor(byte[], int, int, int, int)</a>
-<div class="block"><i>Use
- <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor.TJCompressor(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
+<th class="colDeprecatedItemName" scope="row"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D,int)">org.libjpegturbo.turbojpeg.TJTransformer.transform&#8203;(byte[][], TJTransform[], int)</a></th>
+<td class="colLast">
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform(byte[][], TJTransform[])</code></a> instead.</div>
 </td>
 </tr>
 </tbody>
 </li>
 </ul>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?deprecated-list.html" target="_top">Frames</a></li>
-<li><a href="deprecated-list.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
similarity index 100%
rename from java/doc/package-list
rename to java/doc/element-list
index 6645d95..6d9362c 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>API Help</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?help-doc.html" target="_top">Frames</a></li>
-<li><a href="help-doc.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 class="title">How This API Document Is Organized</h1>
 <div class="subTitle">This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.</div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
+<section>
 <h2>Package</h2>
-<p>Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain six categories:</p>
+<p>Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain six categories:</p>
 <ul>
-<li>Interfaces (italic)</li>
+<li>Interfaces</li>
 <li>Classes</li>
 <li>Enums</li>
 <li>Exceptions</li>
 <li>Errors</li>
 <li>Annotation Types</li>
 </ul>
+</section>
 </li>
 <li class="blockList">
-<h2>Class/Interface</h2>
+<section>
+<h2>Class or Interface</h2>
 <p>Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:</p>
 <ul>
-<li>Class inheritance diagram</li>
+<li>Class Inheritance Diagram</li>
 <li>Direct Subclasses</li>
 <li>All Known Subinterfaces</li>
 <li>All Known Implementing Classes</li>
-<li>Class/interface declaration</li>
-<li>Class/interface description</li>
+<li>Class or Interface Declaration</li>
+<li>Class or Interface Description</li>
 </ul>
+<br>
 <ul>
 <li>Nested Class Summary</li>
 <li>Field Summary</li>
+<li>Property Summary</li>
 <li>Constructor Summary</li>
 <li>Method Summary</li>
 </ul>
+<br>
 <ul>
 <li>Field Detail</li>
+<li>Property Detail</li>
 <li>Constructor Detail</li>
 <li>Method Detail</li>
 </ul>
 <p>Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.</p>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Annotation Type</h2>
 <p>Each annotation type has its own separate page with the following sections:</p>
 <ul>
-<li>Annotation Type declaration</li>
-<li>Annotation Type description</li>
+<li>Annotation Type Declaration</li>
+<li>Annotation Type Description</li>
 <li>Required Element Summary</li>
 <li>Optional Element Summary</li>
 <li>Element Detail</li>
 </ul>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Enum</h2>
 <p>Each enum has its own separate page with the following sections:</p>
 <ul>
-<li>Enum declaration</li>
-<li>Enum description</li>
+<li>Enum Declaration</li>
+<li>Enum Description</li>
 <li>Enum Constant Summary</li>
 <li>Enum Constant Detail</li>
 </ul>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Tree (Class Hierarchy)</h2>
-<p>There is a <a href="overview-tree.html">Class Hierarchy</a> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with <code>java.lang.Object</code>. The interfaces do not inherit from <code>java.lang.Object</code>.</p>
+<p>There is a <a href="overview-tree.html">Class Hierarchy</a> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with <code>java.lang.Object</code>. Interfaces do not inherit from <code>java.lang.Object</code>.</p>
 <ul>
 <li>When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.</li>
-<li>When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.</li>
+<li>When viewing a particular package, class or interface page, clicking on "Tree" displays the hierarchy for only that package.</li>
 </ul>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Deprecated API</h2>
 <p>The <a href="deprecated-list.html">Deprecated API</a> page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.</p>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Index</h2>
-<p>The <a href="index-all.html">Index</a> contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.</p>
+<p>The <a href="index-all.html">Index</a> contains an alphabetic index of all classes, interfaces, constructors, methods, and fields, as well as lists of all packages and all classes.</p>
+</section>
 </li>
 <li class="blockList">
-<h2>Prev/Next</h2>
-<p>These links take you to the next or previous class, interface, package, or related page.</p>
-</li>
-<li class="blockList">
-<h2>Frames/No Frames</h2>
-<p>These links show and hide the HTML frames.  All pages are available with or without frames.</p>
-</li>
-<li class="blockList">
-<h2>All Classes</h2>
-<p>The <a href="allclasses-noframe.html">All Classes</a> link shows all classes and interfaces except non-static nested types.</p>
+<section>
+<h2>All&nbsp;Classes</h2>
+<p>The <a href="allclasses.html">All Classes</a> link shows all classes and interfaces except non-static nested types.</p>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Serialized Form</h2>
 <p>Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description.</p>
+</section>
 </li>
 <li class="blockList">
+<section>
 <h2>Constant Field Values</h2>
 <p>The <a href="constant-values.html">Constant Field Values</a> page lists the static final fields and their values.</p>
+</section>
+</li>
+<li class="blockList">
+<section>
+<h2>Search</h2>
+<p>You can search for definitions of modules, packages, types, fields, methods and other terms defined in the API, using some or all of the name. "Camel-case" abbreviations are supported: for example, "InpStr" will find "InputStream" and "InputStreamReader".</p>
+</section>
 </li>
 </ul>
-<em>This help file applies to API documentation generated using the standard doclet.</em></div>
+<hr>
+<span class="emphasizedPhrase">This help file applies to API documentation generated by the standard doclet.</span></div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?help-doc.html" target="_top">Frames</a></li>
-<li><a href="help-doc.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 5def53e..4b15305 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Index</title>
-<link rel="stylesheet" type="text/css" href="./stylesheet.css" title="Style">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="./org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
 <li>Class</li>
-<li><a href="./org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
-<li><a href="./deprecated-list.html">Deprecated</a></li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
 <li class="navBarCell1Rev">Index</li>
-<li><a href="./help-doc.html">Help</a></li>
+<li><a href="help-doc.html">Help</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="./index.html?index-all.html" target="_top">Frames</a></li>
-<li><a href="index-all.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="./allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
-<div class="contentContainer"><a href="#_B_">B</a>&nbsp;<a href="#_C_">C</a>&nbsp;<a href="#_D_">D</a>&nbsp;<a href="#_E_">E</a>&nbsp;<a href="#_F_">F</a>&nbsp;<a href="#_G_">G</a>&nbsp;<a href="#_H_">H</a>&nbsp;<a href="#_I_">I</a>&nbsp;<a href="#_J_">J</a>&nbsp;<a href="#_N_">N</a>&nbsp;<a href="#_O_">O</a>&nbsp;<a href="#_P_">P</a>&nbsp;<a href="#_S_">S</a>&nbsp;<a href="#_T_">T</a>&nbsp;<a href="#_Y_">Y</a>&nbsp;<a name="_B_">
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
+<div class="contentContainer"><a href="#I:B">B</a>&nbsp;<a href="#I:C">C</a>&nbsp;<a href="#I:D">D</a>&nbsp;<a href="#I:E">E</a>&nbsp;<a href="#I:F">F</a>&nbsp;<a href="#I:G">G</a>&nbsp;<a href="#I:I">I</a>&nbsp;<a href="#I:N">N</a>&nbsp;<a href="#I:O">O</a>&nbsp;<a href="#I:P">P</a>&nbsp;<a href="#I:S">S</a>&nbsp;<a href="#I:T">T</a>&nbsp;<a href="#I:U">U</a>&nbsp;<a href="#I:Y">Y</a>&nbsp;<br><a href="allclasses-index.html">All&nbsp;Classes</a>&nbsp;<a href="allpackages-index.html">All&nbsp;Packages</a><a id="I:B">
 <!--   -->
 </a>
 <h2 class="title">B</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#bufSize(int,%20int,%20int)">bufSize(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#bufSize(int,int,int)">bufSize(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the maximum size of the buffer (in bytes) required to hold a JPEG
  image with the given width, height, and level of chrominance subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)">bufSizeYUV(int, int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,int,int,int)">bufSizeYUV(int, int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Returns the size of the buffer (in bytes) required to hold a YUV planar
- image with the given width, height, and level of chrominance subsampling.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int)">bufSizeYUV(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
-<dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>TJ.bufSizeYUV(int, int, int, int)</code></a> instead.</i></div>
-</div>
+<div class="block">Returns the size of the buffer (in bytes) required to hold a unified
+ planar YUV image with the given width, height, and level of chrominance
+ subsampling.</div>
 </dd>
 </dl>
-<a name="_C_">
+<a id="I:C">
 <!--   -->
 </a>
 <h2 class="title">C</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#cf">cf</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#cf">cf</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Custom filter instance</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#close()">close()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#close()">close()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
 <div class="block">Free the native structures associated with this compressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#close()">close()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#close()">close()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Free the native structures associated with this decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)">compress(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress()">compress()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Compress the uncompressed source image associated with this compressor
instance and output a JPEG image to the given destination buffer.</div>
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
compressor instance and return a buffer containing a JPEG image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)">compress(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte%5B%5D)">compress(byte[])</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Compress the uncompressed source image associated with this compressor
- instance and return a buffer containing a JPEG image.</div>
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
+ compressor instance and output a JPEG image to the given destination
+ buffer.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20byte[],%20int)">compress(BufferedImage, byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte%5B%5D,int)">compress(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)"><code>TJCompressor.compress(byte[], int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte%5B%5D)"><code>TJCompressor.compress(byte[])</code></a> instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20int)">compress(BufferedImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)">compress(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)"><code>TJCompressor.compress(int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#compress()"><code>TJCompressor.compress()</code></a> instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#CS_CMYK">CS_CMYK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_CMYK">CS_CMYK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">CMYK colorspace.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#CS_GRAY">CS_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_GRAY">CS_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Grayscale colorspace.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#CS_RGB">CS_RGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_RGB">CS_RGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">RGB colorspace.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr">CS_YCbCr</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr">CS_YCbCr</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">YCbCr colorspace.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK">CS_YCCK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK">CS_YCCK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">YCCK colorspace.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCustomFilter.html#customFilter(java.nio.ShortBuffer,%20java.awt.Rectangle,%20java.awt.Rectangle,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJTransform)">customFilter(ShortBuffer, Rectangle, Rectangle, int, int, TJTransform)</a></span> - Method in interface org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html#customFilter(java.nio.ShortBuffer,java.awt.Rectangle,java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJTransform)">customFilter(ShortBuffer, Rectangle, Rectangle, int, int, TJTransform)</a></span> - Method in interface org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></dt>
 <dd>
 <div class="block">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.</div>
 </dd>
 </dl>
-<a name="_D_">
+<a id="I:D">
 <!--   -->
 </a>
 <h2 class="title">D</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress(byte[], int, int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte%5B%5D,int,int,int,int,int,int,int)">decompress(byte[], int, int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>,
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(byte%5B%5D,int,int,int,int)"><code>TJDecompressor.decompress8(byte[], int, int, int, int)</code></a> instead.</div>
+</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int%5B%5D,int,int,int,int,int,int,int)">decompress(int[], int, int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int%5B%5D,int,int,int,int)"><code>TJDecompressor.decompress8(int[], int, int, int, int)</code></a>
+ instead.</div>
+</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,int,int,int)">decompress(int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int)"><code>TJDecompressor.decompress8(int)</code></a> instead.</div>
+</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,int,int,int,int)">decompress(int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>,
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int,int)"><code>TJDecompressor.decompress8(int, int)</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int)">decompress(byte[], int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(java.awt.image.BufferedImage,int)">decompress(BufferedImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJDecompressor.decompress(byte[], int, int, int, int, int, int, int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(java.awt.image.BufferedImage)"><code>TJDecompressor.decompress8(BufferedImage)</code></a> instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int,%20int)">decompress(int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress12(int,int)">decompress12(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance and return a buffer containing the decompressed image.</div>
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 12-bit-per-sample
+ packed-pixel decompressed image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress(int[], int, int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress12(short%5B%5D,int,int,int,int)">decompress12(short[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.</div>
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and output a 12-bit-per-sample packed-pixel
grayscale, RGB, or CMYK image to the given destination buffer.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(java.awt.image.BufferedImage,%20int)">decompress(BufferedImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress16(int,int)">decompress16(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a decompressed/decoded image to
the given <code>BufferedImage</code> instance.</div>
+<div class="block">Decompress the 16-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 16-bit-per-sample
packed-pixel decompressed image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int)">decompress(int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress16(short%5B%5D,int,int,int,int)">decompress16(short[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and return a <code>BufferedImage</code>
- instance containing the decompressed/decoded image.</div>
+<div class="block">Decompress the 16-bit-per-sample lossless JPEG source image associated
+ with this decompressor instance and output a 16-bit-per-sample
+ packed-pixel grayscale, RGB, or CMYK image to the given destination
+ buffer.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)">decompressToYUV(YUVImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(byte%5B%5D,int,int,int,int)">decompress8(byte[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a YUV planar image and store it in the given
- <code>YUVImage</code> instance.</div>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(byte[],%20int)">decompressToYUV(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int)">decompress8(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>TJDecompressor.decompressToYUV(YUVImage, int)</code></a> instead.</i></div>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ <code>BufferedImage</code> instance containing the 8-bit-per-sample
+ packed-pixel decompressed/decoded image.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int%5B%5D,int,int,int,int)">decompress8(int[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(int,int)">decompress8(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ buffer containing an 8-bit-per-sample packed-pixel decompressed image.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress8(java.awt.image.BufferedImage)">decompress8(BufferedImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel decompressed/decoded image to the given
+ <code>BufferedImage</code> instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)">decompressToYUV(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample unified planar YUV image
+ and return a <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the decompressed image.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int%5B%5D)">decompressToYUV(int[])</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into a set of 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the
+ decompressed image planes.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,int%5B%5D,int,int)">decompressToYUV(int, int[], int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int%5B%5D)"><code>TJDecompressor.decompressToYUV(int[])</code></a> instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int[],%20int,%20int)">decompressToYUV(int, int[], int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,int,int,int)">decompressToYUV(int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a set of Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the decompressed image planes.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)"><code>TJDecompressor.decompressToYUV(int)</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)">decompressToYUV(int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)">decompressToYUV(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a unified YUV planar image buffer and return a
<code>YUVImage</code> instance containing the decompressed image.</div>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample planar YUV image and store
it in the given <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)">decompressToYUV(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">decompressToYUV(YUVImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)"><code>TJDecompressor.decompressToYUV(int, int, int, int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>set()</code></a>, <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>TJDecompressor.decompressToYUV(YUVImage)</code></a> instead.</div>
 </div>
 </dd>
 </dl>
-<a name="_E_">
+<a id="I:E">
 <!--   -->
 </a>
 <h2 class="title">E</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)">encodeYUV(YUVImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
-<dd>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a YUV planar image and store it in the given
- <code>YUVImage</code> instance.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)">encodeYUV(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int)">encodeYUV(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>TJCompressor.encodeYUV(YUVImage, int)</code></a> instead.</i></div>
-</div>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample unified planar YUV image and
+ return a <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)">encodeYUV(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int%5B%5D)">encodeYUV(int[])</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a unified YUV planar image buffer and return a
- <code>YUVImage</code> instance containing the encoded image.</div>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into separate 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded
+ image planes.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int[],%20int)">encodeYUV(int[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int%5B%5D,int)">encodeYUV(int[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into separate Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the encoded image planes.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int%5B%5D)"><code>TJCompressor.encodeYUV(int[])</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int)">encodeYUV(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,int)">encodeYUV(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>TJCompressor.encodeYUV(int, int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int)"><code>TJCompressor.encodeYUV(int)</code></a> instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20byte[],%20int)">encodeYUV(BufferedImage, byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)">encodeYUV(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)"><code>TJCompressor.encodeYUV(byte[], int)</code></a> instead.</i></div>
-</div>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample planar YUV image and store it
+ in the given <a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20int)">encodeYUV(BufferedImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">encodeYUV(YUVImage, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>TJCompressor.encodeYUV(int, int)</code></a> instead.</i></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set()</code></a> and <a href="org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>TJCompressor.encodeYUV(YUVImage)</code></a>
+ instead.</div>
 </div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">equals(TJScalingFactor)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">equals(TJScalingFactor)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Returns true or false, depending on whether this instance and
  <code>other</code> have the same numerator and denominator.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#ERR_FATAL">ERR_FATAL</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_FATAL">ERR_FATAL</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">The error was fatal and non-recoverable.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#ERR_WARNING">ERR_WARNING</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#ERR_WARNING">ERR_WARNING</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">The error was non-fatal and recoverable, but the image may still be
- corrupt.</div>
+<div class="block">The error was non-fatal and recoverable, but the destination image may
still be corrupt.</div>
 </dd>
 </dl>
-<a name="_F_">
+<a id="I:F">
 <!--   -->
 </a>
 <h2 class="title">F</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#finalize()">finalize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#finalize()">finalize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#finalize()">finalize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#finalize()">finalize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
-<dd>
-<div class="block">Use the most accurate DCT/IDCT algorithm available in the underlying
- codec.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
-<dd>
-<div class="block">The uncompressed source/destination image is stored in bottom-up (Windows,
- OpenGL) order, not top-down (X11) order.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">FLAG_FASTDCT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
-<dd>
-<div class="block">Use the fastest DCT/IDCT algorithm available in the underlying codec.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">When decompressing an image that was compressed using chrominance
- subsampling, use the fastest chrominance upsampling algorithm available in
- the underlying codec.</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCEMMX">FLAG_FORCEMMX</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
-<dd>
-<div class="block"><span class="strong">Deprecated.</span></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT"><code>TJ.PARAM_FASTDCT</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE">FLAG_FORCESSE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_BOTTOMUP"><code>TJ.PARAM_BOTTOMUP</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE2">FLAG_FORCESSE2</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">FLAG_FASTDCT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT"><code>TJ.PARAM_FASTDCT</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE3">FLAG_FORCESSE3</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span></div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTUPSAMPLE"><code>TJ.PARAM_FASTUPSAMPLE</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Limit the number of progressive JPEG scans that the decompression and
- transform operations will process.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SCANLIMIT"><code>TJ.PARAM_SCANLIMIT</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Use progressive entropy coding in JPEG images generated by compression and
- transform operations.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PROGRESSIVE"><code>TJ.PARAM_PROGRESSIVE</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Immediately discontinue the current compression/decompression/transform
- operation if the underlying codec throws a warning (non-fatal error).</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> instead.</div>
+</div>
 </dd>
 </dl>
-<a name="_G_">
+<a id="I:G">
 <!--   -->
 </a>
 <h2 class="title">G</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getAlphaOffset(int)">getAlphaOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#get(int)">get(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">For the given pixel format, returns the number of bytes that the alpha
+<div class="block">Get the value of a compression parameter.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#get(int)">get(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dd>
+<div class="block">Get the value of a decompression parameter.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getAlphaOffset(int)">getAlphaOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">For the given pixel format, returns the number of samples that the alpha
  component is offset from the start of the pixel.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getBlueOffset(int)">getBlueOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getBlueOffset(int)">getBlueOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">For the given pixel format, returns the number of bytes that the blue
+<div class="block">For the given pixel format, returns the number of samples that the blue
  component is offset from the start of the pixel.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getBuf()">getBuf()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getBuf()">getBuf()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Returns the YUV image buffer (if this image is stored in a unified
buffer rather than separate image planes.)</div>
+<div class="block">Returns the YUV buffer (if this image is stored in a unified buffer rather
+ than separate image planes.)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getColorspace()">getColorspace()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getColorspace()">getColorspace()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Returns the colorspace used in the source image (JPEG or YUV) associated
- with this decompressor instance.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#get(int)"><code>get</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_COLORSPACE"><code>TJ.PARAM_COLORSPACE</code></a>)</code>
+ instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#getCompressedSize()">getCompressedSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#getCompressedSize()">getCompressedSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
 <div class="block">Returns the size of the image (in bytes) generated by the most recent
  compress operation.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#getDenom()">getDenom()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getDenom()">getDenom()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Returns denominator</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#getErrorCode()">getErrorCode()</a></span> - Method in exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#getErrorCode()">getErrorCode()</a></span> - Method in exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>
-<div class="block">Returns a code (one of <a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
+<div class="block">Returns a code (one of <a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
  last error.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getGreenOffset(int)">getGreenOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getGreenOffset(int)">getGreenOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">For the given pixel format, returns the number of bytes that the green
+<div class="block">For the given pixel format, returns the number of samples that the green
  component is offset from the start of the pixel.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getHeight()">getHeight()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getHeight()">getHeight()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Returns the height of the source image (JPEG or YUV) associated with this
  decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getHeight()">getHeight()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getHeight()">getHeight()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Returns the height of the YUV image (or subregion.)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGBuf()">getJPEGBuf()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGBuf()">getJPEGBuf()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Returns the JPEG image buffer associated with this decompressor instance.</div>
+<div class="block">Returns the JPEG buffer associated with this decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGSize()">getJPEGSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGSize()">getJPEGSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Returns the size of the JPEG image (in bytes) associated with this
  decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getMCUHeight(int)">getMCUHeight(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getMCUHeight(int)">getMCUHeight(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the MCU block height for the given level of chrominance
  subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getMCUWidth(int)">getMCUWidth(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getMCUWidth(int)">getMCUWidth(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the MCU block width for the given level of chrominance
  subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#getNum()">getNum()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getNum()">getNum()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Returns numerator</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getOffsets()">getOffsets()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getOffsets()">getOffsets()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Returns the offsets (in bytes) of each plane within the planes of a larger
  YUV image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getPad()">getPad()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getPad()">getPad()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Returns the line padding used in the YUV image buffer (if this image is
+<div class="block">Returns the row alignment (in bytes) of the YUV buffer (if this image is
  stored in a unified buffer rather than separate image planes.)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getPixelSize(int)">getPixelSize(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getPixelSize(int)">getPixelSize(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Returns the pixel size (in bytes) for the given pixel format.</div>
+<div class="block">Returns the pixel size (in samples) for the given pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getPlanes()">getPlanes()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getPlanes()">getPlanes()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Returns the YUV image planes.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getRedOffset(int)">getRedOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getRedOffset(int)">getRedOffset(int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">For the given pixel format, returns the number of bytes that the red
+<div class="block">For the given pixel format, returns the number of samples that the red
  component is offset from the start of the pixel.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)">getScaled(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)">getScaled(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Returns the scaled value of <code>dimension</code>.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,%20int)">getScaledHeight(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,int)">getScaledHeight(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Returns the height of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,%20int)">getScaledWidth(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,int)">getScaledWidth(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Returns the width of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#getScalingFactors()">getScalingFactors()</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#getScalingFactors()">getScalingFactors()</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor in
this implementation of TurboJPEG supports.</div>
+<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor
+ supports.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getSize()">getSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getSize()">getSize()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Returns the size (in bytes) of the YUV image buffer (if this image is
stored in a unified buffer rather than separate image planes.)</div>
+<div class="block">Returns the size (in bytes) of the YUV buffer (if this image is stored in
+ a unified buffer rather than separate image planes.)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getStrides()">getStrides()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getStrides()">getStrides()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Returns the number of bytes per line of each plane in the YUV image.</div>
+<div class="block">Returns the number of bytes per row of each plane in the YUV image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getSubsamp()">getSubsamp()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getSubsamp()">getSubsamp()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Returns the level of chrominance subsampling used in the source image
- (JPEG or YUV) associated with this decompressor instance.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#get(int)"><code>get</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>)</code>
+ instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getSubsamp()">getSubsamp()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getSubsamp()">getSubsamp()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Returns the level of chrominance subsampling used in the YUV image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#getTransformedSizes()">getTransformedSizes()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#getTransformedSizes()">getTransformedSizes()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
 <div class="block">Returns an array containing the sizes of the transformed JPEG images
- generated by the most recent transform operation.</div>
(in bytes) generated by the most recent transform operation.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#getWidth()">getWidth()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#getWidth()">getWidth()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Returns the width of the source image (JPEG or YUV) associated with this
  decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#getWidth()">getWidth()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#getWidth()">getWidth()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Returns the width of the YUV image (or subregion.)</div>
 </dd>
 </dl>
-<a name="_H_">
-<!--   -->
-</a>
-<h2 class="title">H</h2>
-<dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#handle">handle</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#handle">handle</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-</dl>
-<a name="_I_">
+<a id="I:I">
 <!--   -->
 </a>
 <h2 class="title">I</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#isOne()">isOne()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#isOne()">isOne()</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Returns true or false, depending on whether this instance is equal to
  1/1.</div>
 </dd>
 </dl>
-<a name="_J_">
-<!--   -->
-</a>
-<h2 class="title">J</h2>
-<dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBuf">jpegBuf</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBufSize">jpegBufSize</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegColorspace">jpegColorspace</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegHeight">jpegHeight</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegSubsamp">jpegSubsamp</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegWidth">jpegWidth</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-</dl>
-<a name="_N_">
+<a id="I:N">
 <!--   -->
 </a>
 <h2 class="title">N</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#NUMCS">NUMCS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMCS">NUMCS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">The number of JPEG colorspaces</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#NUMERR">NUMERR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMERR">NUMERR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">The number of error codes</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#NUMOP">NUMOP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#NUMOP">NUMOP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">The number of lossless transform operations</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#NUMPF">NUMPF</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMPF">NUMPF</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">The number of pixel formats</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#NUMSAMP">NUMSAMP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#NUMSAMP">NUMSAMP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">The number of chrominance subsampling options</div>
 </dd>
 </dl>
-<a name="_O_">
+<a id="I:O">
 <!--   -->
 </a>
 <h2 class="title">O</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#op">op</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#op">op</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">Transform operation (one of <code>OP_*</code>)</div>
+<div class="block">Transform operation (one of <a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE"><code>OP_*</code></a>)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_HFLIP">OP_HFLIP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_HFLIP">OP_HFLIP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Flip (mirror) image horizontally.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE">OP_NONE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE">OP_NONE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Do not transform the position of the image pixels.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT180">OP_ROT180</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT180">OP_ROT180</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Rotate image 180 degrees.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT270">OP_ROT270</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT270">OP_ROT270</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Rotate image counter-clockwise by 90 degrees.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT90">OP_ROT90</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT90">OP_ROT90</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Rotate image clockwise by 90 degrees.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSPOSE">OP_TRANSPOSE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSPOSE">OP_TRANSPOSE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Transpose image (flip/mirror along upper left to lower right axis).</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSVERSE">OP_TRANSVERSE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSVERSE">OP_TRANSVERSE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Transverse transpose image (flip/mirror along upper right to lower left
  axis).</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OP_VFLIP">OP_VFLIP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_VFLIP">OP_VFLIP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Flip (mirror) image vertically.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_COPYNONE">OPT_COPYNONE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_ARITHMETIC">OPT_ARITHMETIC</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">This option will prevent <a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
and ICC profile data) from the source image to the output image.</div>
+<div class="block">This option will enable arithmetic entropy coding in the JPEG image
generated by this particular transform.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_CROP">OPT_CROP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_COPYNONE">OPT_COPYNONE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dd>
+<div class="block">This option will prevent <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
+ and ICC profile data) from the source image to the destination image.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_CROP">OPT_CROP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">This option will enable lossless cropping.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_GRAY">OPT_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_GRAY">OPT_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">This option will discard the color data in the input image and produce
a grayscale output image.</div>
+<div class="block">This option will discard the color data in the source image and produce a
grayscale destination image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_NOOUTPUT">OPT_NOOUTPUT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_NOOUTPUT">OPT_NOOUTPUT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">This option will prevent <a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from outputting a JPEG image for this
+<div class="block">This option will prevent <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> from outputting a JPEG image for this
  particular transform.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT">OPT_PERFECT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_OPTIMIZE">OPT_OPTIMIZE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dd>
+<div class="block">This option will enable optimized baseline entropy coding in the JPEG
+ image generated by this particular transform.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT">OPT_PERFECT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">This option will cause <a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
+<div class="block">This option will cause <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
  perfect.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">This option will enable progressive entropy coding in the output image
+<div class="block">This option will enable progressive entropy coding in the JPEG image
  generated by this particular transform.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#OPT_TRIM">OPT_TRIM</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_TRIM">OPT_TRIM</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">This option will discard any partial MCU blocks that cannot be
  transformed.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#options">options</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#options">options</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
-<div class="block">Transform options (bitwise OR of one or more of <code>OPT_*</code>)</div>
+<div class="block">Transform options (bitwise OR of one or more of
+ <a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_*</code></a>)</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a> - package org.libjpegturbo.turbojpeg</dt>
+<dt><a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a> - package org.libjpegturbo.turbojpeg</dt>
 <dd>&nbsp;</dd>
 </dl>
-<a name="_P_">
+<a id="I:P">
 <!--   -->
 </a>
 <h2 class="title">P</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_ABGR">PF_ABGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_ARITHMETIC">PARAM_ARITHMETIC</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Arithmetic entropy coding</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_BOTTOMUP">PARAM_BOTTOMUP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Row order in packed-pixel source/destination images</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_COLORSPACE">PARAM_COLORSPACE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG colorspace</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_DENSITYUNITS">PARAM_DENSITYUNITS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG pixel density units</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTDCT">PARAM_FASTDCT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">DCT/IDCT algorithm [lossy compression and decompression]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_FASTUPSAMPLE">PARAM_FASTUPSAMPLE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Chrominance upsampling algorithm [lossy decompression only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_JPEGHEIGHT">PARAM_JPEGHEIGHT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG height (in pixels) [decompression only, read-only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_JPEGWIDTH">PARAM_JPEGWIDTH</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG width (in pixels) [decompression only, read-only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESS">PARAM_LOSSLESS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Lossless JPEG</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESSPSV">PARAM_LOSSLESSPSV</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Lossless JPEG predictor selection value (PSV)</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_LOSSLESSPT">PARAM_LOSSLESSPT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Lossless JPEG point transform (Pt)</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_OPTIMIZE">PARAM_OPTIMIZE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Optimized baseline entropy coding [lossy compression only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PRECISION">PARAM_PRECISION</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG data precision (bits per sample) [decompression only, read-only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_PROGRESSIVE">PARAM_PROGRESSIVE</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Progressive entropy coding</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_QUALITY">PARAM_QUALITY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Perceptual quality of lossy JPEG images [compression only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_RESTARTBLOCKS">PARAM_RESTARTBLOCKS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG restart marker interval in MCU blocks (lossy) or samples (lossless)
+ [compression only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_RESTARTROWS">PARAM_RESTARTROWS</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless)
+ [compression only]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SCANLIMIT">PARAM_SCANLIMIT</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
+ transformation]</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_STOPONWARNING">PARAM_STOPONWARNING</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Error handling behavior</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP">PARAM_SUBSAMP</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">Chrominance subsampling level</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_XDENSITY">PARAM_XDENSITY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG horizontal pixel density</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_YDENSITY">PARAM_YDENSITY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">JPEG vertical pixel density</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ABGR">PF_ABGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">ABGR pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_ARGB">PF_ARGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_ARGB">PF_ARGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">ARGB pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_BGR">PF_BGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGR">PF_BGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">BGR pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_BGRA">PF_BGRA</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRA">PF_BGRA</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">BGRA pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX">PF_BGRX</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX">PF_BGRX</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">BGRX pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_CMYK">PF_CMYK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_CMYK">PF_CMYK</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">CMYK pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_GRAY">PF_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_GRAY">PF_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Grayscale pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_RGB">PF_RGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGB">PF_RGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">RGB pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_RGBA">PF_RGBA</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBA">PF_RGBA</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">RGBA pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX">PF_RGBX</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX">PF_RGBX</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">RGBX pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR">PF_XBGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR">PF_XBGR</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">XBGR pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB">PF_XRGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB">PF_XRGB</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">XRGB pixel format.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#planeHeight(int,%20int,%20int)">planeHeight(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#planeHeight(int,int,int)">planeHeight(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the plane height of a YUV image plane with the given parameters.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#planeSizeYUV(int,%20int,%20int,%20int,%20int)">planeSizeYUV(int, int, int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#planeSizeYUV(int,int,int,int,int)">planeSizeYUV(int, int, int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the size of the buffer (in bytes) required to hold a YUV image
  plane with the given parameters.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#planeWidth(int,%20int,%20int)">planeWidth(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#planeWidth(int,int,int)">planeWidth(int, int, int)</a></span> - Static method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Returns the plane width of a YUV image plane with the given parameters.</div>
 </dd>
 </dl>
-<a name="_S_">
+<a id="I:S">
 <!--   -->
 </a>
 <h2 class="title">S</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_411">SAMP_411</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_411">SAMP_411</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">4:1:1 chrominance subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_420">SAMP_420</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_420">SAMP_420</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">4:2:0 chrominance subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_422">SAMP_422</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_422">SAMP_422</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">4:2:2 chrominance subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_440">SAMP_440</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_440">SAMP_440</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">4:4:0 chrominance subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_444">SAMP_444</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_441">SAMP_441</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dd>
+<div class="block">4:4:1 chrominance subsampling.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_444">SAMP_444</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">4:4:4 chrominance subsampling (no chrominance subsampling).</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJ.html#SAMP_GRAY">SAMP_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_GRAY">SAMP_GRAY</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
 <div class="block">Grayscale.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte[][],%20int[],%20int,%20int[],%20int,%20int)">setBuf(byte[][], int[], int, int[], int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#SAMP_UNKNOWN">SAMP_UNKNOWN</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Assign a set of image planes to this <code>YUVImage</code> instance.</div>
+<div class="block">Unknown subsampling.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte[],%20int,%20int,%20int,%20int)">setBuf(byte[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)">set(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Assign a unified image buffer to this <code>YUVImage</code> instance.</div>
+<div class="block">Set the value of a compression parameter.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#setJPEGImage(byte[],%20int)">setJPEGImage(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)">set(int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use <a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)"><code>TJDecompressor.setSourceImage(byte[], int)</code></a> instead.</i></div>
-</div>
+<div class="block">Set the value of a decompression parameter.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setJPEGQuality(int)">setJPEGQuality(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte%5B%5D%5B%5D,int%5B%5D,int,int%5B%5D,int,int)">setBuf(byte[][], int[], int, int[], int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Set the JPEG image quality level for subsequent compress operations.</div>
+<div class="block">Assign a set of image planes to this <code>YUVImage</code> instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)">setSourceImage(byte[], int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte%5B%5D,int,int,int,int)">setBuf(byte[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Associate an uncompressed RGB, grayscale, or CMYK source image with this
- compressor instance.</div>
+<div class="block">Assign a unified buffer to this <code>YUVImage</code> instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int)">setSourceImage(byte[], int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setCroppingRegion(java.awt.Rectangle)">setCroppingRegion(Rectangle)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor.setSourceImage(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-</div>
+<div class="block">Set the cropping region for partially decompressing a lossy JPEG image
+ into a packed-pixel image.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)">setSourceImage(BufferedImage, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setJPEGQuality(int)">setJPEGQuality(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Associate an uncompressed RGB or grayscale source image with this
- compressor instance.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_QUALITY"><code>TJ.PARAM_QUALITY</code></a>, ...)</code> instead.</div>
+</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)">setScalingFactor(TJScalingFactor)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Associate an uncompressed YUV planar source image with this compressor
- instance.</div>
+<div class="block">Set the scaling factor for subsequent lossy decompression operations.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)">setSourceImage(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte%5B%5D,int)">setSourceImage(byte[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Associate the JPEG image or "abbreviated table specification" (AKA
  "tables-only") datastream of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with this decompressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte%5B%5D,int,int,int,int,int,int)">setSourceImage(byte[], int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dd>
+<div class="block">Associate an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)">setSourceImage(BufferedImage, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dd>
+<div class="block">Associate an 8-bit-per-pixel packed-pixel RGB or grayscale source image
+ with this compressor instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dd>
+<div class="block">Associate an 8-bit-per-sample planar YUV source image with this compressor
+ instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage(YUVImage)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Associate the specified YUV planar source image with this decompressor
+<div class="block">Associate the specified planar YUV source image with this decompressor
  instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSubsamp(int)">setSubsamp(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage12(short%5B%5D,int,int,int,int,int,int)">setSourceImage12(short[], int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dd>
+<div class="block">Associate a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage16(short%5B%5D,int,int,int,int,int,int)">setSourceImage16(short[], int, int, int, int, int, int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Set the level of chrominance subsampling for subsequent compress/encode
- operations.</div>
+<div class="block">Associate a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#setSubsamp(int)">setSubsamp(int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#set(int,int)"><code>set</code></a>(<a href="org/libjpegturbo/turbojpeg/TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>, ...)</code> instead.</div>
+</div>
 </dd>
 </dl>
-<a name="_T_">
+<a id="I:T">
 <!--   -->
 </a>
 <h2 class="title">T</h2>
 <dl>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJ</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJ</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">TurboJPEG utility class (cannot be instantiated)</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJCompressor</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCompressor</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">TurboJPEG compressor</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor()">TJCompressor()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#%3Cinit%3E()">TJCompressor()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG compressor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)">TJCompressor(byte[], int, int, int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#%3Cinit%3E(byte%5B%5D,int,int,int,int,int,int)">TJCompressor(byte[], int, int, int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
created instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int)">TJCompressor(byte[], int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJCompressor.html#%3Cinit%3E(java.awt.image.BufferedImage,int,int,int,int)">TJCompressor(BufferedImage, int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
 <dd>
-<div class="block"><span class="strong">Deprecated.</span>
-<div class="block"><i>Use
- <a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor.TJCompressor(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-</div>
-</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)">TJCompressor(BufferedImage, int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></dt>
-<dd>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
+ created instance.</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">TJCustomFilter</span></a> - Interface in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCustomFilter</span></a> - Interface in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">Custom filter callback interface</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJDecompressor</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJDecompressor</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">TurboJPEG decompressor</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor()">TJDecompressor()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#%3Cinit%3E()">TJDecompressor()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG decompresssor instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(byte[])">TJDecompressor(byte[])</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#%3Cinit%3E(byte%5B%5D)">TJDecompressor(byte[])</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image stored in <code>jpegImage</code> with the newly created instance.</div>
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ stored in <code>jpegImage</code> with the newly created instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(byte[],%20int)">TJDecompressor(byte[], int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#%3Cinit%3E(byte%5B%5D,int)">TJDecompressor(byte[], int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image of length <code>imageSize</code> bytes stored in
- <code>jpegImage</code> with the newly created instance.</div>
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
+ with the newly created instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(org.libjpegturbo.turbojpeg.YUVImage)">TJDecompressor(YUVImage)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#%3Cinit%3E(org.libjpegturbo.turbojpeg.YUVImage)">TJDecompressor(YUVImage)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
 <dd>
-<div class="block">Create a TurboJPEG decompressor instance and associate the YUV planar
- source image stored in <code>yuvImage</code> with the newly created
- instance.</div>
+<div class="block">Create a TurboJPEG decompressor instance and associate the
+ 8-bit-per-sample planar YUV source image stored in <code>yuvImage</code>
with the newly created instance.</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJException</span></a> - Exception in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJException</span></a> - Exception in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#TJException()">TJException()</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#%3Cinit%3E()">TJException()</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String,%20java.lang.Throwable)">TJException(String, Throwable)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#%3Cinit%3E(java.lang.String)">TJException(String)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String)">TJException(String)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#%3Cinit%3E(java.lang.String,int)">TJException(String, int)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String,%20int)">TJException(String, int)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#%3Cinit%3E(java.lang.String,java.lang.Throwable)">TJException(String, Throwable)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.Throwable)">TJException(Throwable)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJException.html#%3Cinit%3E(java.lang.Throwable)">TJException(Throwable)</a></span> - Constructor for exception org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></dt>
 <dd>&nbsp;</dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJScalingFactor</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJScalingFactor</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">Fractional scaling factor</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html#TJScalingFactor(int,%20int)">TJScalingFactor(int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html#%3Cinit%3E(int,int)">TJScalingFactor(int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG scaling factor instance.</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransform</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransform</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">Lossless transform parameters</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform()">TJTransform()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#%3Cinit%3E()">TJTransform()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Create a new lossless transform instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform(int,%20int,%20int,%20int,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform(int, int, int, int, int, int, TJCustomFilter)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#%3Cinit%3E(int,int,int,int,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform(int, int, int, int, int, int, TJCustomFilter)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform(java.awt.Rectangle,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform(Rectangle, int, int, TJCustomFilter)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransform.html#%3Cinit%3E(java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform(Rectangle, int, int, TJCustomFilter)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></dt>
 <dd>
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
 </dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransformer</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransformer</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
 <div class="block">TurboJPEG lossless transformer</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer()">TJTransformer()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#%3Cinit%3E()">TJTransformer()</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG lossless transformer instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer(byte[])">TJTransformer(byte[])</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#%3Cinit%3E(byte%5B%5D)">TJTransformer(byte[])</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image stored in <code>jpegImage</code> with the newly created instance.</div>
+ source image stored in <code>jpegImage</code> with the newly created
+ instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer(byte[],%20int)">TJTransformer(byte[], int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#%3Cinit%3E(byte%5B%5D,int)">TJTransformer(byte[], int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image of length <code>imageSize</code> bytes stored in
source image of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with the newly created instance.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)">transform(byte[][], TJTransform[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)">transform(byte[][], TJTransform[])</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dd>
+<div class="block">Losslessly transform the JPEG source image associated with this
+ transformer instance into one or more JPEG images stored in the given
+ destination buffers.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D,int)">transform(byte[][], TJTransform[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dd>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform(byte[][], TJTransform[])</code></a> instead.</div>
+</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D)">transform(TJTransform[])</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
- instance into one or more JPEG images stored in the given destination
buffers.</div>
+<div class="block">Losslessly transform the JPEG source image associated with this
+ transformer instance and return an array of <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a>
instances, each of which has a transformed JPEG image associated with it.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJTransformer.html#transform(org.libjpegturbo.turbojpeg.TJTransform[],%20int)">transform(TJTransform[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D,int)">transform(TJTransform[], int)</a></span> - Method in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dt>
 <dd>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
- instance and return an array of <a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a> instances, each of
- which has a transformed JPEG image associated with it.</div>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="org/libjpegturbo/turbojpeg/TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="org/libjpegturbo/turbojpeg/TJTransformer.html#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform(TJTransform[])</code></a> instead.</div>
+</div>
 </dd>
 </dl>
-<a name="_Y_">
+<a id="I:U">
 <!--   -->
 </a>
-<h2 class="title">Y</h2>
+<h2 class="title">U</h2>
 <dl>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvHeight">yuvHeight</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html#yuvImage">yuvImage</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></dt>
-<dd>&nbsp;</dd>
-<dt><a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">YUVImage</span></a> - Class in <a href="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#UNCROPPED">UNCROPPED</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">This class encapsulates a YUV planar image and the metadata
- associated with it.</div>
+<div class="block">A <code>java.awt.Rectangle</code> instance that specifies no cropping</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(int,%20int[],%20int,%20int)">YUVImage(int, int[], int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/TJ.html#UNSCALED">UNSCALED</a></span> - Static variable in class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></dt>
 <dd>
-<div class="block">Create a new <code>YUVImage</code> instance backed by separate image
planes, and allocate memory for the image planes.</div>
+<div class="block">A <a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJScalingFactor</code></a> instance that specifies a scaling factor of 1/1
(no scaling)</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(int,%20int,%20int,%20int)">YUVImage(int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+</dl>
+<a id="I:Y">
+<!--   -->
+</a>
+<h2 class="title">Y</h2>
+<dl>
+<dt><a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">YUVImage</span></a> - Class in <a href="org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</a></dt>
 <dd>
-<div class="block">Create a new <code>YUVImage</code> instance backed by a unified image
buffer, and allocate memory for the image buffer.</div>
+<div class="block">This class encapsulates a planar YUV image and the metadata
associated with it.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(byte[][],%20int[],%20int,%20int[],%20int,%20int)">YUVImage(byte[][], int[], int, int[], int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#%3Cinit%3E(byte%5B%5D%5B%5D,int%5B%5D,int,int%5B%5D,int,int)">YUVImage(byte[][], int[], int, int[], int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
 <div class="block">Create a new <code>YUVImage</code> instance from a set of existing image
  planes.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(byte[],%20int,%20int,%20int,%20int)">YUVImage(byte[], int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#%3Cinit%3E(byte%5B%5D,int,int,int,int)">YUVImage(byte[], int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
 <dd>
-<div class="block">Create a new <code>YUVImage</code> instance from an existing unified image
+<div class="block">Create a new <code>YUVImage</code> instance from an existing unified
  buffer.</div>
 </dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvOffsets">yuvOffsets</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvPad">yuvPad</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvPlanes">yuvPlanes</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvStrides">yuvStrides</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvSubsamp">yuvSubsamp</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
-<dt><span class="strong"><a href="./org/libjpegturbo/turbojpeg/YUVImage.html#yuvWidth">yuvWidth</a></span> - Variable in class org.libjpegturbo.turbojpeg.<a href="./org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
-<dd>&nbsp;</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#%3Cinit%3E(int,int%5B%5D,int,int)">YUVImage(int, int[], int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dd>
+<div class="block">Create a new <code>YUVImage</code> instance backed by separate image
+ planes, and allocate memory for the image planes.</div>
+</dd>
+<dt><span class="memberNameLink"><a href="org/libjpegturbo/turbojpeg/YUVImage.html#%3Cinit%3E(int,int,int,int)">YUVImage(int, int, int, int)</a></span> - Constructor for class org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></dt>
+<dd>
+<div class="block">Create a new <code>YUVImage</code> instance backed by a unified buffer,
+ and allocate memory for the buffer.</div>
+</dd>
 </dl>
-<a href="#_B_">B</a>&nbsp;<a href="#_C_">C</a>&nbsp;<a href="#_D_">D</a>&nbsp;<a href="#_E_">E</a>&nbsp;<a href="#_F_">F</a>&nbsp;<a href="#_G_">G</a>&nbsp;<a href="#_H_">H</a>&nbsp;<a href="#_I_">I</a>&nbsp;<a href="#_J_">J</a>&nbsp;<a href="#_N_">N</a>&nbsp;<a href="#_O_">O</a>&nbsp;<a href="#_P_">P</a>&nbsp;<a href="#_S_">S</a>&nbsp;<a href="#_T_">T</a>&nbsp;<a href="#_Y_">Y</a>&nbsp;</div>
+<a href="#I:B">B</a>&nbsp;<a href="#I:C">C</a>&nbsp;<a href="#I:D">D</a>&nbsp;<a href="#I:E">E</a>&nbsp;<a href="#I:F">F</a>&nbsp;<a href="#I:G">G</a>&nbsp;<a href="#I:I">I</a>&nbsp;<a href="#I:N">N</a>&nbsp;<a href="#I:O">O</a>&nbsp;<a href="#I:P">P</a>&nbsp;<a href="#I:S">S</a>&nbsp;<a href="#I:T">T</a>&nbsp;<a href="#I:U">U</a>&nbsp;<a href="#I:Y">Y</a>&nbsp;<br><a href="allclasses-index.html">All&nbsp;Classes</a>&nbsp;<a href="allpackages-index.html">All&nbsp;Packages</a></div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="./org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
 <li>Class</li>
-<li><a href="./org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
-<li><a href="./deprecated-list.html">Deprecated</a></li>
+<li><a href="org/libjpegturbo/turbojpeg/package-tree.html">Tree</a></li>
+<li><a href="deprecated-list.html">Deprecated</a></li>
 <li class="navBarCell1Rev">Index</li>
-<li><a href="./help-doc.html">Help</a></li>
+<li><a href="help-doc.html">Help</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="./index.html?index-all.html" target="_top">Frames</a></li>
-<li><a href="index-all.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="./allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 4e21075..cae2fdd 100644 (file)
@@ -1,71 +1,23 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Generated Documentation (Untitled)</title>
-<script type="text/javascript">
-    tmpTargetPage = "" + window.location.search;
-    if (tmpTargetPage != "" && tmpTargetPage != "undefined")
-        tmpTargetPage = tmpTargetPage.substring(1);
-    if (tmpTargetPage.indexOf(":") != -1 || (tmpTargetPage != "" && !validURL(tmpTargetPage)))
-        tmpTargetPage = "undefined";
-    targetPage = tmpTargetPage;
-    function validURL(url) {
-        try {
-            url = decodeURIComponent(url);
-        }
-        catch (error) {
-            return false;
-        }
-        var pos = url.indexOf(".html");
-        if (pos == -1 || pos != url.length - 5)
-            return false;
-        var allowNumber = false;
-        var allowSep = false;
-        var seenDot = false;
-        for (var i = 0; i < url.length - 5; i++) {
-            var ch = url.charAt(i);
-            if ('a' <= ch && ch <= 'z' ||
-                    'A' <= ch && ch <= 'Z' ||
-                    ch == '$' ||
-                    ch == '_' ||
-                    ch.charCodeAt(0) > 127) {
-                allowNumber = true;
-                allowSep = true;
-            } else if ('0' <= ch && ch <= '9'
-                    || ch == '-') {
-                if (!allowNumber)
-                     return false;
-            } else if (ch == '/' || ch == '.') {
-                if (!allowSep)
-                    return false;
-                allowNumber = false;
-                allowSep = false;
-                if (ch == '.')
-                     seenDot = true;
-                if (ch == '/' && seenDot)
-                     return false;
-            } else {
-                return false;
-            }
-        }
-        return true;
-    }
-    function loadFrames() {
-        if (targetPage != "" && targetPage != "undefined")
-             top.classFrame.location = top.targetPage;
-    }
-</script>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<script type="text/javascript">window.location.replace('org/libjpegturbo/turbojpeg/package-summary.html')</script>
+<noscript>
+<meta http-equiv="Refresh" content="0;org/libjpegturbo/turbojpeg/package-summary.html">
+</noscript>
+<link rel="canonical" href="org/libjpegturbo/turbojpeg/package-summary.html">
+<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
 </head>
-<frameset cols="20%,80%" title="Documentation frame" onload="top.loadFrames()">
-<frame src="allclasses-frame.html" name="packageFrame" title="All classes and interfaces (except non-static nested types)">
-<frame src="org/libjpegturbo/turbojpeg/package-summary.html" name="classFrame" title="Package, class and interface descriptions" scrolling="yes">
-<noframes>
+<body>
+<main role="main">
 <noscript>
-<div>JavaScript is disabled on your browser.</div>
+<p>JavaScript is disabled on your browser.</p>
 </noscript>
-<h2>Frame Alert</h2>
-<p>This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. Link to <a href="org/libjpegturbo/turbojpeg/package-summary.html">Non-frame version</a>.</p>
-</noframes>
-</frameset>
+<p><a href="org/libjpegturbo/turbojpeg/package-summary.html">org/libjpegturbo/turbojpeg/package-summary.html</a></p>
+</main>
+</body>
 </html>
diff --git a/java/doc/jquery-ui.overrides.css b/java/doc/jquery-ui.overrides.css
new file mode 100644 (file)
index 0000000..facf852
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active,
+a.ui-button:active,
+.ui-button:active,
+.ui-button.ui-state-active:hover {
+    /* Overrides the color of selection used in jQuery UI */
+    background: #F8981D;
+    border: 1px solid #F8981D;
+}
diff --git a/java/doc/jquery/external/jquery/jquery.js b/java/doc/jquery/external/jquery/jquery.js
new file mode 100644 (file)
index 0000000..5093733
--- /dev/null
@@ -0,0 +1,10872 @@
+/*!
+ * jQuery JavaScript Library v3.5.1
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2020-05-04T22:49Z
+ */
+( function( global, factory ) {
+
+       "use strict";
+
+       if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+               // For CommonJS and CommonJS-like environments where a proper `window`
+               // is present, execute the factory and get jQuery.
+               // For environments that do not have a `window` with a `document`
+               // (such as Node.js), expose a factory as module.exports.
+               // This accentuates the need for the creation of a real `window`.
+               // e.g. var jQuery = require("jquery")(window);
+               // See ticket #14549 for more info.
+               module.exports = global.document ?
+                       factory( global, true ) :
+                       function( w ) {
+                               if ( !w.document ) {
+                                       throw new Error( "jQuery requires a window with a document" );
+                               }
+                               return factory( w );
+                       };
+       } else {
+               factory( global );
+       }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+       return arr.flat.call( array );
+} : function( array ) {
+       return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+      // Support: Chrome <=57, Firefox <=52
+      // In some browsers, typeof returns "function" for HTML <object> elements
+      // (i.e., `typeof document.createElement( "object" ) === "function"`).
+      // We don't want to classify *any* DOM node as a function.
+      return typeof obj === "function" && typeof obj.nodeType !== "number";
+  };
+
+
+var isWindow = function isWindow( obj ) {
+               return obj != null && obj === obj.window;
+       };
+
+
+var document = window.document;
+
+
+
+       var preservedScriptAttributes = {
+               type: true,
+               src: true,
+               nonce: true,
+               noModule: true
+       };
+
+       function DOMEval( code, node, doc ) {
+               doc = doc || document;
+
+               var i, val,
+                       script = doc.createElement( "script" );
+
+               script.text = code;
+               if ( node ) {
+                       for ( i in preservedScriptAttributes ) {
+
+                               // Support: Firefox 64+, Edge 18+
+                               // Some browsers don't support the "nonce" property on scripts.
+                               // On the other hand, just using `getAttribute` is not enough as
+                               // the `nonce` attribute is reset to an empty string whenever it
+                               // becomes browsing-context connected.
+                               // See https://github.com/whatwg/html/issues/2369
+                               // See https://html.spec.whatwg.org/#nonce-attributes
+                               // The `node.getAttribute` check was added for the sake of
+                               // `jQuery.globalEval` so that it can fake a nonce-containing node
+                               // via an object.
+                               val = node[ i ] || node.getAttribute && node.getAttribute( i );
+                               if ( val ) {
+                                       script.setAttribute( i, val );
+                               }
+                       }
+               }
+               doc.head.appendChild( script ).parentNode.removeChild( script );
+       }
+
+
+function toType( obj ) {
+       if ( obj == null ) {
+               return obj + "";
+       }
+
+       // Support: Android <=2.3 only (functionish RegExp)
+       return typeof obj === "object" || typeof obj === "function" ?
+               class2type[ toString.call( obj ) ] || "object" :
+               typeof obj;
+}
+/* global Symbol */
+// Defining this global in .eslintrc.json would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
+
+
+
+var
+       version = "3.5.1",
+
+       // Define a local copy of jQuery
+       jQuery = function( selector, context ) {
+
+               // The jQuery object is actually just the init constructor 'enhanced'
+               // Need init if jQuery is called (just allow error to be thrown if not included)
+               return new jQuery.fn.init( selector, context );
+       };
+
+jQuery.fn = jQuery.prototype = {
+
+       // The current version of jQuery being used
+       jquery: version,
+
+       constructor: jQuery,
+
+       // The default length of a jQuery object is 0
+       length: 0,
+
+       toArray: function() {
+               return slice.call( this );
+       },
+
+       // Get the Nth element in the matched element set OR
+       // Get the whole matched element set as a clean array
+       get: function( num ) {
+
+               // Return all the elements in a clean array
+               if ( num == null ) {
+                       return slice.call( this );
+               }
+
+               // Return just the one element from the set
+               return num < 0 ? this[ num + this.length ] : this[ num ];
+       },
+
+       // Take an array of elements and push it onto the stack
+       // (returning the new matched element set)
+       pushStack: function( elems ) {
+
+               // Build a new jQuery matched element set
+               var ret = jQuery.merge( this.constructor(), elems );
+
+               // Add the old object onto the stack (as a reference)
+               ret.prevObject = this;
+
+               // Return the newly-formed element set
+               return ret;
+       },
+
+       // Execute a callback for every element in the matched set.
+       each: function( callback ) {
+               return jQuery.each( this, callback );
+       },
+
+       map: function( callback ) {
+               return this.pushStack( jQuery.map( this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               } ) );
+       },
+
+       slice: function() {
+               return this.pushStack( slice.apply( this, arguments ) );
+       },
+
+       first: function() {
+               return this.eq( 0 );
+       },
+
+       last: function() {
+               return this.eq( -1 );
+       },
+
+       even: function() {
+               return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+                       return ( i + 1 ) % 2;
+               } ) );
+       },
+
+       odd: function() {
+               return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+                       return i % 2;
+               } ) );
+       },
+
+       eq: function( i ) {
+               var len = this.length,
+                       j = +i + ( i < 0 ? len : 0 );
+               return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
+       },
+
+       end: function() {
+               return this.prevObject || this.constructor();
+       },
+
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: push,
+       sort: arr.sort,
+       splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+       var options, name, src, copy, copyIsArray, clone,
+               target = arguments[ 0 ] || {},
+               i = 1,
+               length = arguments.length,
+               deep = false;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+
+               // Skip the boolean and the target
+               target = arguments[ i ] || {};
+               i++;
+       }
+
+       // Handle case when target is a string or something (possible in deep copy)
+       if ( typeof target !== "object" && !isFunction( target ) ) {
+               target = {};
+       }
+
+       // Extend jQuery itself if only one argument is passed
+       if ( i === length ) {
+               target = this;
+               i--;
+       }
+
+       for ( ; i < length; i++ ) {
+
+               // Only deal with non-null/undefined values
+               if ( ( options = arguments[ i ] ) != null ) {
+
+                       // Extend the base object
+                       for ( name in options ) {
+                               copy = options[ name ];
+
+                               // Prevent Object.prototype pollution
+                               // Prevent never-ending loop
+                               if ( name === "__proto__" || target === copy ) {
+                                       continue;
+                               }
+
+                               // Recurse if we're merging plain objects or arrays
+                               if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+                                       ( copyIsArray = Array.isArray( copy ) ) ) ) {
+                                       src = target[ name ];
+
+                                       // Ensure proper type for the source value
+                                       if ( copyIsArray && !Array.isArray( src ) ) {
+                                               clone = [];
+                                       } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
+                                               clone = {};
+                                       } else {
+                                               clone = src;
+                                       }
+                                       copyIsArray = false;
+
+                                       // Never move original objects, clone them
+                                       target[ name ] = jQuery.extend( deep, clone, copy );
+
+                               // Don't bring in undefined values
+                               } else if ( copy !== undefined ) {
+                                       target[ name ] = copy;
+                               }
+                       }
+               }
+       }
+
+       // Return the modified object
+       return target;
+};
+
+jQuery.extend( {
+
+       // Unique for each copy of jQuery on the page
+       expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+       // Assume jQuery is ready without the ready module
+       isReady: true,
+
+       error: function( msg ) {
+               throw new Error( msg );
+       },
+
+       noop: function() {},
+
+       isPlainObject: function( obj ) {
+               var proto, Ctor;
+
+               // Detect obvious negatives
+               // Use toString instead of jQuery.type to catch host objects
+               if ( !obj || toString.call( obj ) !== "[object Object]" ) {
+                       return false;
+               }
+
+               proto = getProto( obj );
+
+               // Objects with no prototype (e.g., `Object.create( null )`) are plain
+               if ( !proto ) {
+                       return true;
+               }
+
+               // Objects with prototype are plain iff they were constructed by a global Object function
+               Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+               return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
+       },
+
+       isEmptyObject: function( obj ) {
+               var name;
+
+               for ( name in obj ) {
+                       return false;
+               }
+               return true;
+       },
+
+       // Evaluates a script in a provided context; falls back to the global one
+       // if not specified.
+       globalEval: function( code, options, doc ) {
+               DOMEval( code, { nonce: options && options.nonce }, doc );
+       },
+
+       each: function( obj, callback ) {
+               var length, i = 0;
+
+               if ( isArrayLike( obj ) ) {
+                       length = obj.length;
+                       for ( ; i < length; i++ ) {
+                               if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+                                       break;
+                               }
+                       }
+               } else {
+                       for ( i in obj ) {
+                               if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+                                       break;
+                               }
+                       }
+               }
+
+               return obj;
+       },
+
+       // results is for internal usage only
+       makeArray: function( arr, results ) {
+               var ret = results || [];
+
+               if ( arr != null ) {
+                       if ( isArrayLike( Object( arr ) ) ) {
+                               jQuery.merge( ret,
+                                       typeof arr === "string" ?
+                                       [ arr ] : arr
+                               );
+                       } else {
+                               push.call( ret, arr );
+                       }
+               }
+
+               return ret;
+       },
+
+       inArray: function( elem, arr, i ) {
+               return arr == null ? -1 : indexOf.call( arr, elem, i );
+       },
+
+       // Support: Android <=4.0 only, PhantomJS 1 only
+       // push.apply(_, arraylike) throws on ancient WebKit
+       merge: function( first, second ) {
+               var len = +second.length,
+                       j = 0,
+                       i = first.length;
+
+               for ( ; j < len; j++ ) {
+                       first[ i++ ] = second[ j ];
+               }
+
+               first.length = i;
+
+               return first;
+       },
+
+       grep: function( elems, callback, invert ) {
+               var callbackInverse,
+                       matches = [],
+                       i = 0,
+                       length = elems.length,
+                       callbackExpect = !invert;
+
+               // Go through the array, only saving the items
+               // that pass the validator function
+               for ( ; i < length; i++ ) {
+                       callbackInverse = !callback( elems[ i ], i );
+                       if ( callbackInverse !== callbackExpect ) {
+                               matches.push( elems[ i ] );
+                       }
+               }
+
+               return matches;
+       },
+
+       // arg is for internal usage only
+       map: function( elems, callback, arg ) {
+               var length, value,
+                       i = 0,
+                       ret = [];
+
+               // Go through the array, translating each of the items to their new values
+               if ( isArrayLike( elems ) ) {
+                       length = elems.length;
+                       for ( ; i < length; i++ ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+
+               // Go through every key on the object,
+               } else {
+                       for ( i in elems ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret.push( value );
+                               }
+                       }
+               }
+
+               // Flatten any nested arrays
+               return flat( ret );
+       },
+
+       // A global GUID counter for objects
+       guid: 1,
+
+       // jQuery.support is not used in Core but other projects attach their
+       // properties to it so it needs to exist.
+       support: support
+} );
+
+if ( typeof Symbol === "function" ) {
+       jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
+
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( _i, name ) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+} );
+
+function isArrayLike( obj ) {
+
+       // Support: real iOS 8.2 only (not reproducible in simulator)
+       // `in` check used to prevent JIT error (gh-2145)
+       // hasOwn isn't used here due to false negatives
+       // regarding Nodelist length in IE
+       var length = !!obj && "length" in obj && obj.length,
+               type = toType( obj );
+
+       if ( isFunction( obj ) || isWindow( obj ) ) {
+               return false;
+       }
+
+       return type === "array" || length === 0 ||
+               typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.3.5
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://js.foundation/
+ *
+ * Date: 2020-03-14
+ */
+( function( window ) {
+var i,
+       support,
+       Expr,
+       getText,
+       isXML,
+       tokenize,
+       compile,
+       select,
+       outermostContext,
+       sortInput,
+       hasDuplicate,
+
+       // Local document vars
+       setDocument,
+       document,
+       docElem,
+       documentIsHTML,
+       rbuggyQSA,
+       rbuggyMatches,
+       matches,
+       contains,
+
+       // Instance-specific data
+       expando = "sizzle" + 1 * new Date(),
+       preferredDoc = window.document,
+       dirruns = 0,
+       done = 0,
+       classCache = createCache(),
+       tokenCache = createCache(),
+       compilerCache = createCache(),
+       nonnativeSelectorCache = createCache(),
+       sortOrder = function( a, b ) {
+               if ( a === b ) {
+                       hasDuplicate = true;
+               }
+               return 0;
+       },
+
+       // Instance methods
+       hasOwn = ( {} ).hasOwnProperty,
+       arr = [],
+       pop = arr.pop,
+       pushNative = arr.push,
+       push = arr.push,
+       slice = arr.slice,
+
+       // Use a stripped-down indexOf as it's faster than native
+       // https://jsperf.com/thor-indexof-vs-for/5
+       indexOf = function( list, elem ) {
+               var i = 0,
+                       len = list.length;
+               for ( ; i < len; i++ ) {
+                       if ( list[ i ] === elem ) {
+                               return i;
+                       }
+               }
+               return -1;
+       },
+
+       booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
+               "ismap|loop|multiple|open|readonly|required|scoped",
+
+       // Regular expressions
+
+       // http://www.w3.org/TR/css3-selectors/#whitespace
+       whitespace = "[\\x20\\t\\r\\n\\f]",
+
+       // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
+       identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
+               "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
+
+       // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+       attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+
+               // Operator (capture 2)
+               "*([*^$|!~]?=)" + whitespace +
+
+               // "Attribute values must be CSS identifiers [capture 5]
+               // or strings [capture 3 or capture 4]"
+               "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
+               whitespace + "*\\]",
+
+       pseudos = ":(" + identifier + ")(?:\\((" +
+
+               // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+               // 1. quoted (capture 3; capture 4 or capture 5)
+               "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+
+               // 2. simple (capture 6)
+               "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+
+               // 3. anything else (capture 2)
+               ".*" +
+               ")\\)|)",
+
+       // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+       rwhitespace = new RegExp( whitespace + "+", "g" ),
+       rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
+               whitespace + "+$", "g" ),
+
+       rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+       rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
+               "*" ),
+       rdescend = new RegExp( whitespace + "|>" ),
+
+       rpseudo = new RegExp( pseudos ),
+       ridentifier = new RegExp( "^" + identifier + "$" ),
+
+       matchExpr = {
+               "ID": new RegExp( "^#(" + identifier + ")" ),
+               "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+               "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+               "ATTR": new RegExp( "^" + attributes ),
+               "PSEUDO": new RegExp( "^" + pseudos ),
+               "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+                       whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+                       whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+               "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+
+               // For use in libraries implementing .is()
+               // We use this for POS matching in `select`
+               "needsContext": new RegExp( "^" + whitespace +
+                       "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+                       "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+       },
+
+       rhtml = /HTML$/i,
+       rinputs = /^(?:input|select|textarea|button)$/i,
+       rheader = /^h\d$/i,
+
+       rnative = /^[^{]+\{\s*\[native \w/,
+
+       // Easily-parseable/retrievable ID or TAG or CLASS selectors
+       rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+       rsibling = /[+~]/,
+
+       // CSS escapes
+       // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+       runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+       funescape = function( escape, nonHex ) {
+               var high = "0x" + escape.slice( 1 ) - 0x10000;
+
+               return nonHex ?
+
+                       // Strip the backslash prefix from a non-hex escape sequence
+                       nonHex :
+
+                       // Replace a hexadecimal escape sequence with the encoded Unicode code point
+                       // Support: IE <=11+
+                       // For values outside the Basic Multilingual Plane (BMP), manually construct a
+                       // surrogate pair
+                       high < 0 ?
+                               String.fromCharCode( high + 0x10000 ) :
+                               String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+       },
+
+       // CSS string/identifier serialization
+       // https://drafts.csswg.org/cssom/#common-serializing-idioms
+       rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
+       fcssescape = function( ch, asCodePoint ) {
+               if ( asCodePoint ) {
+
+                       // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+                       if ( ch === "\0" ) {
+                               return "\uFFFD";
+                       }
+
+                       // Control characters and (dependent upon position) numbers get escaped as code points
+                       return ch.slice( 0, -1 ) + "\\" +
+                               ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+               }
+
+               // Other potentially-special ASCII characters get backslash-escaped
+               return "\\" + ch;
+       },
+
+       // Used for iframes
+       // See setDocument()
+       // Removing the function wrapper causes a "Permission Denied"
+       // error in IE
+       unloadHandler = function() {
+               setDocument();
+       },
+
+       inDisabledFieldset = addCombinator(
+               function( elem ) {
+                       return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
+               },
+               { dir: "parentNode", next: "legend" }
+       );
+
+// Optimize for push.apply( _, NodeList )
+try {
+       push.apply(
+               ( arr = slice.call( preferredDoc.childNodes ) ),
+               preferredDoc.childNodes
+       );
+
+       // Support: Android<4.0
+       // Detect silently failing push.apply
+       // eslint-disable-next-line no-unused-expressions
+       arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+       push = { apply: arr.length ?
+
+               // Leverage slice if possible
+               function( target, els ) {
+                       pushNative.apply( target, slice.call( els ) );
+               } :
+
+               // Support: IE<9
+               // Otherwise append directly
+               function( target, els ) {
+                       var j = target.length,
+                               i = 0;
+
+                       // Can't trust NodeList.length
+                       while ( ( target[ j++ ] = els[ i++ ] ) ) {}
+                       target.length = j - 1;
+               }
+       };
+}
+
+function Sizzle( selector, context, results, seed ) {
+       var m, i, elem, nid, match, groups, newSelector,
+               newContext = context && context.ownerDocument,
+
+               // nodeType defaults to 9, since context defaults to document
+               nodeType = context ? context.nodeType : 9;
+
+       results = results || [];
+
+       // Return early from calls with invalid selector or context
+       if ( typeof selector !== "string" || !selector ||
+               nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+               return results;
+       }
+
+       // Try to shortcut find operations (as opposed to filters) in HTML documents
+       if ( !seed ) {
+               setDocument( context );
+               context = context || document;
+
+               if ( documentIsHTML ) {
+
+                       // If the selector is sufficiently simple, try using a "get*By*" DOM method
+                       // (excepting DocumentFragment context, where the methods don't exist)
+                       if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
+
+                               // ID selector
+                               if ( ( m = match[ 1 ] ) ) {
+
+                                       // Document context
+                                       if ( nodeType === 9 ) {
+                                               if ( ( elem = context.getElementById( m ) ) ) {
+
+                                                       // Support: IE, Opera, Webkit
+                                                       // TODO: identify versions
+                                                       // getElementById can match elements by name instead of ID
+                                                       if ( elem.id === m ) {
+                                                               results.push( elem );
+                                                               return results;
+                                                       }
+                                               } else {
+                                                       return results;
+                                               }
+
+                                       // Element context
+                                       } else {
+
+                                               // Support: IE, Opera, Webkit
+                                               // TODO: identify versions
+                                               // getElementById can match elements by name instead of ID
+                                               if ( newContext && ( elem = newContext.getElementById( m ) ) &&
+                                                       contains( context, elem ) &&
+                                                       elem.id === m ) {
+
+                                                       results.push( elem );
+                                                       return results;
+                                               }
+                                       }
+
+                               // Type selector
+                               } else if ( match[ 2 ] ) {
+                                       push.apply( results, context.getElementsByTagName( selector ) );
+                                       return results;
+
+                               // Class selector
+                               } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
+                                       context.getElementsByClassName ) {
+
+                                       push.apply( results, context.getElementsByClassName( m ) );
+                                       return results;
+                               }
+                       }
+
+                       // Take advantage of querySelectorAll
+                       if ( support.qsa &&
+                               !nonnativeSelectorCache[ selector + " " ] &&
+                               ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
+
+                               // Support: IE 8 only
+                               // Exclude object elements
+                               ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
+
+                               newSelector = selector;
+                               newContext = context;
+
+                               // qSA considers elements outside a scoping root when evaluating child or
+                               // descendant combinators, which is not what we want.
+                               // In such cases, we work around the behavior by prefixing every selector in the
+                               // list with an ID selector referencing the scope context.
+                               // The technique has to be used as well when a leading combinator is used
+                               // as such selectors are not recognized by querySelectorAll.
+                               // Thanks to Andrew Dupont for this technique.
+                               if ( nodeType === 1 &&
+                                       ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
+
+                                       // Expand context for sibling selectors
+                                       newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+                                               context;
+
+                                       // We can use :scope instead of the ID hack if the browser
+                                       // supports it & if we're not changing the context.
+                                       if ( newContext !== context || !support.scope ) {
+
+                                               // Capture the context ID, setting it first if necessary
+                                               if ( ( nid = context.getAttribute( "id" ) ) ) {
+                                                       nid = nid.replace( rcssescape, fcssescape );
+                                               } else {
+                                                       context.setAttribute( "id", ( nid = expando ) );
+                                               }
+                                       }
+
+                                       // Prefix every selector in the list
+                                       groups = tokenize( selector );
+                                       i = groups.length;
+                                       while ( i-- ) {
+                                               groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+                                                       toSelector( groups[ i ] );
+                                       }
+                                       newSelector = groups.join( "," );
+                               }
+
+                               try {
+                                       push.apply( results,
+                                               newContext.querySelectorAll( newSelector )
+                                       );
+                                       return results;
+                               } catch ( qsaError ) {
+                                       nonnativeSelectorCache( selector, true );
+                               } finally {
+                                       if ( nid === expando ) {
+                                               context.removeAttribute( "id" );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       // All others
+       return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ *     property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ *     deleting the oldest entry
+ */
+function createCache() {
+       var keys = [];
+
+       function cache( key, value ) {
+
+               // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+               if ( keys.push( key + " " ) > Expr.cacheLength ) {
+
+                       // Only keep the most recent entries
+                       delete cache[ keys.shift() ];
+               }
+               return ( cache[ key + " " ] = value );
+       }
+       return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+       fn[ expando ] = true;
+       return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created element and returns a boolean result
+ */
+function assert( fn ) {
+       var el = document.createElement( "fieldset" );
+
+       try {
+               return !!fn( el );
+       } catch ( e ) {
+               return false;
+       } finally {
+
+               // Remove from its parent by default
+               if ( el.parentNode ) {
+                       el.parentNode.removeChild( el );
+               }
+
+               // release memory in IE
+               el = null;
+       }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+       var arr = attrs.split( "|" ),
+               i = arr.length;
+
+       while ( i-- ) {
+               Expr.attrHandle[ arr[ i ] ] = handler;
+       }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+       var cur = b && a,
+               diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+                       a.sourceIndex - b.sourceIndex;
+
+       // Use IE sourceIndex if available on both nodes
+       if ( diff ) {
+               return diff;
+       }
+
+       // Check if b follows a
+       if ( cur ) {
+               while ( ( cur = cur.nextSibling ) ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+               }
+       }
+
+       return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return name === "input" && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+       return function( elem ) {
+               var name = elem.nodeName.toLowerCase();
+               return ( name === "input" || name === "button" ) && elem.type === type;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+
+       // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+       return function( elem ) {
+
+               // Only certain elements can match :enabled or :disabled
+               // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
+               // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
+               if ( "form" in elem ) {
+
+                       // Check for inherited disabledness on relevant non-disabled elements:
+                       // * listed form-associated elements in a disabled fieldset
+                       //   https://html.spec.whatwg.org/multipage/forms.html#category-listed
+                       //   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
+                       // * option elements in a disabled optgroup
+                       //   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
+                       // All such elements have a "form" property.
+                       if ( elem.parentNode && elem.disabled === false ) {
+
+                               // Option elements defer to a parent optgroup if present
+                               if ( "label" in elem ) {
+                                       if ( "label" in elem.parentNode ) {
+                                               return elem.parentNode.disabled === disabled;
+                                       } else {
+                                               return elem.disabled === disabled;
+                                       }
+                               }
+
+                               // Support: IE 6 - 11
+                               // Use the isDisabled shortcut property to check for disabled fieldset ancestors
+                               return elem.isDisabled === disabled ||
+
+                                       // Where there is no isDisabled, check manually
+                                       /* jshint -W018 */
+                                       elem.isDisabled !== !disabled &&
+                                       inDisabledFieldset( elem ) === disabled;
+                       }
+
+                       return elem.disabled === disabled;
+
+               // Try to winnow out elements that can't be disabled before trusting the disabled property.
+               // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
+               // even exist on them, let alone have a boolean value.
+               } else if ( "label" in elem ) {
+                       return elem.disabled === disabled;
+               }
+
+               // Remaining elements are neither :enabled nor :disabled
+               return false;
+       };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+       return markFunction( function( argument ) {
+               argument = +argument;
+               return markFunction( function( seed, matches ) {
+                       var j,
+                               matchIndexes = fn( [], seed.length, argument ),
+                               i = matchIndexes.length;
+
+                       // Match elements found at the specified indexes
+                       while ( i-- ) {
+                               if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
+                                       seed[ j ] = !( matches[ j ] = seed[ j ] );
+                               }
+                       }
+               } );
+       } );
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+       return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+       var namespace = elem.namespaceURI,
+               docElem = ( elem.ownerDocument || elem ).documentElement;
+
+       // Support: IE <=8
+       // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
+       // https://bugs.jquery.com/ticket/4833
+       return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+       var hasCompare, subWindow,
+               doc = node ? node.ownerDocument || node : preferredDoc;
+
+       // Return early if doc is invalid or already selected
+       // Support: IE 11+, Edge 17 - 18+
+       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+       // two documents; shallow comparisons work.
+       // eslint-disable-next-line eqeqeq
+       if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
+               return document;
+       }
+
+       // Update global variables
+       document = doc;
+       docElem = document.documentElement;
+       documentIsHTML = !isXML( document );
+
+       // Support: IE 9 - 11+, Edge 12 - 18+
+       // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+       // Support: IE 11+, Edge 17 - 18+
+       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+       // two documents; shallow comparisons work.
+       // eslint-disable-next-line eqeqeq
+       if ( preferredDoc != document &&
+               ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
+
+               // Support: IE 11, Edge
+               if ( subWindow.addEventListener ) {
+                       subWindow.addEventListener( "unload", unloadHandler, false );
+
+               // Support: IE 9 - 10 only
+               } else if ( subWindow.attachEvent ) {
+                       subWindow.attachEvent( "onunload", unloadHandler );
+               }
+       }
+
+       // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
+       // Safari 4 - 5 only, Opera <=11.6 - 12.x only
+       // IE/Edge & older browsers don't support the :scope pseudo-class.
+       // Support: Safari 6.0 only
+       // Safari 6.0 supports :scope but it's an alias of :root there.
+       support.scope = assert( function( el ) {
+               docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
+               return typeof el.querySelectorAll !== "undefined" &&
+                       !el.querySelectorAll( ":scope fieldset div" ).length;
+       } );
+
+       /* Attributes
+       ---------------------------------------------------------------------- */
+
+       // Support: IE<8
+       // Verify that getAttribute really returns attributes and not properties
+       // (excepting IE8 booleans)
+       support.attributes = assert( function( el ) {
+               el.className = "i";
+               return !el.getAttribute( "className" );
+       } );
+
+       /* getElement(s)By*
+       ---------------------------------------------------------------------- */
+
+       // Check if getElementsByTagName("*") returns only elements
+       support.getElementsByTagName = assert( function( el ) {
+               el.appendChild( document.createComment( "" ) );
+               return !el.getElementsByTagName( "*" ).length;
+       } );
+
+       // Support: IE<9
+       support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+       // Support: IE<10
+       // Check if getElementById returns elements by name
+       // The broken getElementById methods don't pick up programmatically-set names,
+       // so use a roundabout getElementsByName test
+       support.getById = assert( function( el ) {
+               docElem.appendChild( el ).id = expando;
+               return !document.getElementsByName || !document.getElementsByName( expando ).length;
+       } );
+
+       // ID filter and find
+       if ( support.getById ) {
+               Expr.filter[ "ID" ] = function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               return elem.getAttribute( "id" ) === attrId;
+                       };
+               };
+               Expr.find[ "ID" ] = function( id, context ) {
+                       if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+                               var elem = context.getElementById( id );
+                               return elem ? [ elem ] : [];
+                       }
+               };
+       } else {
+               Expr.filter[ "ID" ] =  function( id ) {
+                       var attrId = id.replace( runescape, funescape );
+                       return function( elem ) {
+                               var node = typeof elem.getAttributeNode !== "undefined" &&
+                                       elem.getAttributeNode( "id" );
+                               return node && node.value === attrId;
+                       };
+               };
+
+               // Support: IE 6 - 7 only
+               // getElementById is not reliable as a find shortcut
+               Expr.find[ "ID" ] = function( id, context ) {
+                       if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+                               var node, i, elems,
+                                       elem = context.getElementById( id );
+
+                               if ( elem ) {
+
+                                       // Verify the id attribute
+                                       node = elem.getAttributeNode( "id" );
+                                       if ( node && node.value === id ) {
+                                               return [ elem ];
+                                       }
+
+                                       // Fall back on getElementsByName
+                                       elems = context.getElementsByName( id );
+                                       i = 0;
+                                       while ( ( elem = elems[ i++ ] ) ) {
+                                               node = elem.getAttributeNode( "id" );
+                                               if ( node && node.value === id ) {
+                                                       return [ elem ];
+                                               }
+                                       }
+                               }
+
+                               return [];
+                       }
+               };
+       }
+
+       // Tag
+       Expr.find[ "TAG" ] = support.getElementsByTagName ?
+               function( tag, context ) {
+                       if ( typeof context.getElementsByTagName !== "undefined" ) {
+                               return context.getElementsByTagName( tag );
+
+                       // DocumentFragment nodes don't have gEBTN
+                       } else if ( support.qsa ) {
+                               return context.querySelectorAll( tag );
+                       }
+               } :
+
+               function( tag, context ) {
+                       var elem,
+                               tmp = [],
+                               i = 0,
+
+                               // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+                               results = context.getElementsByTagName( tag );
+
+                       // Filter out possible comments
+                       if ( tag === "*" ) {
+                               while ( ( elem = results[ i++ ] ) ) {
+                                       if ( elem.nodeType === 1 ) {
+                                               tmp.push( elem );
+                                       }
+                               }
+
+                               return tmp;
+                       }
+                       return results;
+               };
+
+       // Class
+       Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
+               if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+                       return context.getElementsByClassName( className );
+               }
+       };
+
+       /* QSA/matchesSelector
+       ---------------------------------------------------------------------- */
+
+       // QSA and matchesSelector support
+
+       // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+       rbuggyMatches = [];
+
+       // qSa(:focus) reports false when true (Chrome 21)
+       // We allow this because of a bug in IE8/9 that throws an error
+       // whenever `document.activeElement` is accessed on an iframe
+       // So, we allow :focus to pass through QSA all the time to avoid the IE error
+       // See https://bugs.jquery.com/ticket/13378
+       rbuggyQSA = [];
+
+       if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
+
+               // Build QSA regex
+               // Regex strategy adopted from Diego Perini
+               assert( function( el ) {
+
+                       var input;
+
+                       // Select is set to empty string on purpose
+                       // This is to test IE's treatment of not explicitly
+                       // setting a boolean content attribute,
+                       // since its presence should be enough
+                       // https://bugs.jquery.com/ticket/12359
+                       docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+                               "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+                               "<option selected=''></option></select>";
+
+                       // Support: IE8, Opera 11-12.16
+                       // Nothing should be selected when empty strings follow ^= or $= or *=
+                       // The test attribute must be unknown in Opera but "safe" for WinRT
+                       // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+                       if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
+                               rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+                       }
+
+                       // Support: IE8
+                       // Boolean attributes and "value" are not treated correctly
+                       if ( !el.querySelectorAll( "[selected]" ).length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+                       }
+
+                       // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+                       if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+                               rbuggyQSA.push( "~=" );
+                       }
+
+                       // Support: IE 11+, Edge 15 - 18+
+                       // IE 11/Edge don't find elements on a `[name='']` query in some cases.
+                       // Adding a temporary attribute to the document before the selection works
+                       // around the issue.
+                       // Interestingly, IE 10 & older don't seem to have the issue.
+                       input = document.createElement( "input" );
+                       input.setAttribute( "name", "" );
+                       el.appendChild( input );
+                       if ( !el.querySelectorAll( "[name='']" ).length ) {
+                               rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+                                       whitespace + "*(?:''|\"\")" );
+                       }
+
+                       // Webkit/Opera - :checked should return selected option elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       // IE8 throws error here and will not see later tests
+                       if ( !el.querySelectorAll( ":checked" ).length ) {
+                               rbuggyQSA.push( ":checked" );
+                       }
+
+                       // Support: Safari 8+, iOS 8+
+                       // https://bugs.webkit.org/show_bug.cgi?id=136851
+                       // In-page `selector#id sibling-combinator selector` fails
+                       if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+                               rbuggyQSA.push( ".#.+[+~]" );
+                       }
+
+                       // Support: Firefox <=3.6 - 5 only
+                       // Old Firefox doesn't throw on a badly-escaped identifier.
+                       el.querySelectorAll( "\\\f" );
+                       rbuggyQSA.push( "[\\r\\n\\f]" );
+               } );
+
+               assert( function( el ) {
+                       el.innerHTML = "<a href='' disabled='disabled'></a>" +
+                               "<select disabled='disabled'><option/></select>";
+
+                       // Support: Windows 8 Native Apps
+                       // The type and name attributes are restricted during .innerHTML assignment
+                       var input = document.createElement( "input" );
+                       input.setAttribute( "type", "hidden" );
+                       el.appendChild( input ).setAttribute( "name", "D" );
+
+                       // Support: IE8
+                       // Enforce case-sensitivity of name attribute
+                       if ( el.querySelectorAll( "[name=d]" ).length ) {
+                               rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+                       }
+
+                       // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+                       // IE8 throws error here and will not see later tests
+                       if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
+
+                       // Support: IE9-11+
+                       // IE's :disabled selector does not pick up the children of disabled fieldsets
+                       docElem.appendChild( el ).disabled = true;
+                       if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
+                               rbuggyQSA.push( ":enabled", ":disabled" );
+                       }
+
+                       // Support: Opera 10 - 11 only
+                       // Opera 10-11 does not throw on post-comma invalid pseudos
+                       el.querySelectorAll( "*,:x" );
+                       rbuggyQSA.push( ",.*:" );
+               } );
+       }
+
+       if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
+               docElem.webkitMatchesSelector ||
+               docElem.mozMatchesSelector ||
+               docElem.oMatchesSelector ||
+               docElem.msMatchesSelector ) ) ) ) {
+
+               assert( function( el ) {
+
+                       // Check to see if it's possible to do matchesSelector
+                       // on a disconnected node (IE 9)
+                       support.disconnectedMatch = matches.call( el, "*" );
+
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( el, "[s!='']:x" );
+                       rbuggyMatches.push( "!=", pseudos );
+               } );
+       }
+
+       rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
+       rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
+
+       /* Contains
+       ---------------------------------------------------------------------- */
+       hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+       // Element contains another
+       // Purposefully self-exclusive
+       // As in, an element does not contain itself
+       contains = hasCompare || rnative.test( docElem.contains ) ?
+               function( a, b ) {
+                       var adown = a.nodeType === 9 ? a.documentElement : a,
+                               bup = b && b.parentNode;
+                       return a === bup || !!( bup && bup.nodeType === 1 && (
+                               adown.contains ?
+                                       adown.contains( bup ) :
+                                       a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+                       ) );
+               } :
+               function( a, b ) {
+                       if ( b ) {
+                               while ( ( b = b.parentNode ) ) {
+                                       if ( b === a ) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               };
+
+       /* Sorting
+       ---------------------------------------------------------------------- */
+
+       // Document order sorting
+       sortOrder = hasCompare ?
+       function( a, b ) {
+
+               // Flag for duplicate removal
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               // Sort on method existence if only one input has compareDocumentPosition
+               var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+               if ( compare ) {
+                       return compare;
+               }
+
+               // Calculate position if both inputs belong to the same document
+               // Support: IE 11+, Edge 17 - 18+
+               // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+               // two documents; shallow comparisons work.
+               // eslint-disable-next-line eqeqeq
+               compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
+                       a.compareDocumentPosition( b ) :
+
+                       // Otherwise we know they are disconnected
+                       1;
+
+               // Disconnected nodes
+               if ( compare & 1 ||
+                       ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
+
+                       // Choose the first element that is related to our preferred document
+                       // Support: IE 11+, Edge 17 - 18+
+                       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                       // two documents; shallow comparisons work.
+                       // eslint-disable-next-line eqeqeq
+                       if ( a == document || a.ownerDocument == preferredDoc &&
+                               contains( preferredDoc, a ) ) {
+                               return -1;
+                       }
+
+                       // Support: IE 11+, Edge 17 - 18+
+                       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                       // two documents; shallow comparisons work.
+                       // eslint-disable-next-line eqeqeq
+                       if ( b == document || b.ownerDocument == preferredDoc &&
+                               contains( preferredDoc, b ) ) {
+                               return 1;
+                       }
+
+                       // Maintain original order
+                       return sortInput ?
+                               ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+                               0;
+               }
+
+               return compare & 4 ? -1 : 1;
+       } :
+       function( a, b ) {
+
+               // Exit early if the nodes are identical
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               var cur,
+                       i = 0,
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       ap = [ a ],
+                       bp = [ b ];
+
+               // Parentless nodes are either documents or disconnected
+               if ( !aup || !bup ) {
+
+                       // Support: IE 11+, Edge 17 - 18+
+                       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                       // two documents; shallow comparisons work.
+                       /* eslint-disable eqeqeq */
+                       return a == document ? -1 :
+                               b == document ? 1 :
+                               /* eslint-enable eqeqeq */
+                               aup ? -1 :
+                               bup ? 1 :
+                               sortInput ?
+                               ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+                               0;
+
+               // If the nodes are siblings, we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+               }
+
+               // Otherwise we need full lists of their ancestors for comparison
+               cur = a;
+               while ( ( cur = cur.parentNode ) ) {
+                       ap.unshift( cur );
+               }
+               cur = b;
+               while ( ( cur = cur.parentNode ) ) {
+                       bp.unshift( cur );
+               }
+
+               // Walk down the tree looking for a discrepancy
+               while ( ap[ i ] === bp[ i ] ) {
+                       i++;
+               }
+
+               return i ?
+
+                       // Do a sibling check if the nodes have a common ancestor
+                       siblingCheck( ap[ i ], bp[ i ] ) :
+
+                       // Otherwise nodes in our document sort first
+                       // Support: IE 11+, Edge 17 - 18+
+                       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                       // two documents; shallow comparisons work.
+                       /* eslint-disable eqeqeq */
+                       ap[ i ] == preferredDoc ? -1 :
+                       bp[ i ] == preferredDoc ? 1 :
+                       /* eslint-enable eqeqeq */
+                       0;
+       };
+
+       return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+       return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+       setDocument( elem );
+
+       if ( support.matchesSelector && documentIsHTML &&
+               !nonnativeSelectorCache[ expr + " " ] &&
+               ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+               ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
+
+               try {
+                       var ret = matches.call( elem, expr );
+
+                       // IE 9's matchesSelector returns false on disconnected nodes
+                       if ( ret || support.disconnectedMatch ||
+
+                               // As well, disconnected nodes are said to be in a document
+                               // fragment in IE 9
+                               elem.document && elem.document.nodeType !== 11 ) {
+                               return ret;
+                       }
+               } catch ( e ) {
+                       nonnativeSelectorCache( expr, true );
+               }
+       }
+
+       return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+
+       // Set document vars if needed
+       // Support: IE 11+, Edge 17 - 18+
+       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+       // two documents; shallow comparisons work.
+       // eslint-disable-next-line eqeqeq
+       if ( ( context.ownerDocument || context ) != document ) {
+               setDocument( context );
+       }
+       return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+
+       // Set document vars if needed
+       // Support: IE 11+, Edge 17 - 18+
+       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+       // two documents; shallow comparisons work.
+       // eslint-disable-next-line eqeqeq
+       if ( ( elem.ownerDocument || elem ) != document ) {
+               setDocument( elem );
+       }
+
+       var fn = Expr.attrHandle[ name.toLowerCase() ],
+
+               // Don't get fooled by Object.prototype properties (jQuery #13807)
+               val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+                       fn( elem, name, !documentIsHTML ) :
+                       undefined;
+
+       return val !== undefined ?
+               val :
+               support.attributes || !documentIsHTML ?
+                       elem.getAttribute( name ) :
+                       ( val = elem.getAttributeNode( name ) ) && val.specified ?
+                               val.value :
+                               null;
+};
+
+Sizzle.escape = function( sel ) {
+       return ( sel + "" ).replace( rcssescape, fcssescape );
+};
+
+Sizzle.error = function( msg ) {
+       throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+       var elem,
+               duplicates = [],
+               j = 0,
+               i = 0;
+
+       // Unless we *know* we can detect duplicates, assume their presence
+       hasDuplicate = !support.detectDuplicates;
+       sortInput = !support.sortStable && results.slice( 0 );
+       results.sort( sortOrder );
+
+       if ( hasDuplicate ) {
+               while ( ( elem = results[ i++ ] ) ) {
+                       if ( elem === results[ i ] ) {
+                               j = duplicates.push( i );
+                       }
+               }
+               while ( j-- ) {
+                       results.splice( duplicates[ j ], 1 );
+               }
+       }
+
+       // Clear input after sorting to release objects
+       // See https://github.com/jquery/sizzle/pull/225
+       sortInput = null;
+
+       return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+       var node,
+               ret = "",
+               i = 0,
+               nodeType = elem.nodeType;
+
+       if ( !nodeType ) {
+
+               // If no nodeType, this is expected to be an array
+               while ( ( node = elem[ i++ ] ) ) {
+
+                       // Do not traverse comment nodes
+                       ret += getText( node );
+               }
+       } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+
+               // Use textContent for elements
+               // innerText usage removed for consistency of new lines (jQuery #11153)
+               if ( typeof elem.textContent === "string" ) {
+                       return elem.textContent;
+               } else {
+
+                       // Traverse its children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               ret += getText( elem );
+                       }
+               }
+       } else if ( nodeType === 3 || nodeType === 4 ) {
+               return elem.nodeValue;
+       }
+
+       // Do not include comment or processing instruction nodes
+
+       return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+       // Can be adjusted by the user
+       cacheLength: 50,
+
+       createPseudo: markFunction,
+
+       match: matchExpr,
+
+       attrHandle: {},
+
+       find: {},
+
+       relative: {
+               ">": { dir: "parentNode", first: true },
+               " ": { dir: "parentNode" },
+               "+": { dir: "previousSibling", first: true },
+               "~": { dir: "previousSibling" }
+       },
+
+       preFilter: {
+               "ATTR": function( match ) {
+                       match[ 1 ] = match[ 1 ].replace( runescape, funescape );
+
+                       // Move the given value to match[3] whether quoted or unquoted
+                       match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
+                               match[ 5 ] || "" ).replace( runescape, funescape );
+
+                       if ( match[ 2 ] === "~=" ) {
+                               match[ 3 ] = " " + match[ 3 ] + " ";
+                       }
+
+                       return match.slice( 0, 4 );
+               },
+
+               "CHILD": function( match ) {
+
+                       /* matches from matchExpr["CHILD"]
+                               1 type (only|nth|...)
+                               2 what (child|of-type)
+                               3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+                               4 xn-component of xn+y argument ([+-]?\d*n|)
+                               5 sign of xn-component
+                               6 x of xn-component
+                               7 sign of y-component
+                               8 y of y-component
+                       */
+                       match[ 1 ] = match[ 1 ].toLowerCase();
+
+                       if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
+
+                               // nth-* requires argument
+                               if ( !match[ 3 ] ) {
+                                       Sizzle.error( match[ 0 ] );
+                               }
+
+                               // numeric x and y parameters for Expr.filter.CHILD
+                               // remember that false/true cast respectively to 0/1
+                               match[ 4 ] = +( match[ 4 ] ?
+                                       match[ 5 ] + ( match[ 6 ] || 1 ) :
+                                       2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+                               match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
+
+                               // other types prohibit arguments
+                       } else if ( match[ 3 ] ) {
+                               Sizzle.error( match[ 0 ] );
+                       }
+
+                       return match;
+               },
+
+               "PSEUDO": function( match ) {
+                       var excess,
+                               unquoted = !match[ 6 ] && match[ 2 ];
+
+                       if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
+                               return null;
+                       }
+
+                       // Accept quoted arguments as-is
+                       if ( match[ 3 ] ) {
+                               match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
+
+                       // Strip excess characters from unquoted arguments
+                       } else if ( unquoted && rpseudo.test( unquoted ) &&
+
+                               // Get excess from tokenize (recursively)
+                               ( excess = tokenize( unquoted, true ) ) &&
+
+                               // advance to the next closing parenthesis
+                               ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
+
+                               // excess is a negative index
+                               match[ 0 ] = match[ 0 ].slice( 0, excess );
+                               match[ 2 ] = unquoted.slice( 0, excess );
+                       }
+
+                       // Return only captures needed by the pseudo filter method (type and argument)
+                       return match.slice( 0, 3 );
+               }
+       },
+
+       filter: {
+
+               "TAG": function( nodeNameSelector ) {
+                       var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+                       return nodeNameSelector === "*" ?
+                               function() {
+                                       return true;
+                               } :
+                               function( elem ) {
+                                       return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+                               };
+               },
+
+               "CLASS": function( className ) {
+                       var pattern = classCache[ className + " " ];
+
+                       return pattern ||
+                               ( pattern = new RegExp( "(^|" + whitespace +
+                                       ")" + className + "(" + whitespace + "|$)" ) ) && classCache(
+                                               className, function( elem ) {
+                                                       return pattern.test(
+                                                               typeof elem.className === "string" && elem.className ||
+                                                               typeof elem.getAttribute !== "undefined" &&
+                                                                       elem.getAttribute( "class" ) ||
+                                                               ""
+                                                       );
+                               } );
+               },
+
+               "ATTR": function( name, operator, check ) {
+                       return function( elem ) {
+                               var result = Sizzle.attr( elem, name );
+
+                               if ( result == null ) {
+                                       return operator === "!=";
+                               }
+                               if ( !operator ) {
+                                       return true;
+                               }
+
+                               result += "";
+
+                               /* eslint-disable max-len */
+
+                               return operator === "=" ? result === check :
+                                       operator === "!=" ? result !== check :
+                                       operator === "^=" ? check && result.indexOf( check ) === 0 :
+                                       operator === "*=" ? check && result.indexOf( check ) > -1 :
+                                       operator === "$=" ? check && result.slice( -check.length ) === check :
+                                       operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+                                       operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+                                       false;
+                               /* eslint-enable max-len */
+
+                       };
+               },
+
+               "CHILD": function( type, what, _argument, first, last ) {
+                       var simple = type.slice( 0, 3 ) !== "nth",
+                               forward = type.slice( -4 ) !== "last",
+                               ofType = what === "of-type";
+
+                       return first === 1 && last === 0 ?
+
+                               // Shortcut for :nth-*(n)
+                               function( elem ) {
+                                       return !!elem.parentNode;
+                               } :
+
+                               function( elem, _context, xml ) {
+                                       var cache, uniqueCache, outerCache, node, nodeIndex, start,
+                                               dir = simple !== forward ? "nextSibling" : "previousSibling",
+                                               parent = elem.parentNode,
+                                               name = ofType && elem.nodeName.toLowerCase(),
+                                               useCache = !xml && !ofType,
+                                               diff = false;
+
+                                       if ( parent ) {
+
+                                               // :(first|last|only)-(child|of-type)
+                                               if ( simple ) {
+                                                       while ( dir ) {
+                                                               node = elem;
+                                                               while ( ( node = node[ dir ] ) ) {
+                                                                       if ( ofType ?
+                                                                               node.nodeName.toLowerCase() === name :
+                                                                               node.nodeType === 1 ) {
+
+                                                                               return false;
+                                                                       }
+                                                               }
+
+                                                               // Reverse direction for :only-* (if we haven't yet done so)
+                                                               start = dir = type === "only" && !start && "nextSibling";
+                                                       }
+                                                       return true;
+                                               }
+
+                                               start = [ forward ? parent.firstChild : parent.lastChild ];
+
+                                               // non-xml :nth-child(...) stores cache data on `parent`
+                                               if ( forward && useCache ) {
+
+                                                       // Seek `elem` from a previously-cached index
+
+                                                       // ...in a gzip-friendly way
+                                                       node = parent;
+                                                       outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+                                                       // Support: IE <9 only
+                                                       // Defend against cloned attroperties (jQuery gh-1709)
+                                                       uniqueCache = outerCache[ node.uniqueID ] ||
+                                                               ( outerCache[ node.uniqueID ] = {} );
+
+                                                       cache = uniqueCache[ type ] || [];
+                                                       nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+                                                       diff = nodeIndex && cache[ 2 ];
+                                                       node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+                                                       while ( ( node = ++nodeIndex && node && node[ dir ] ||
+
+                                                               // Fallback to seeking `elem` from the start
+                                                               ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+                                                               // When found, cache indexes on `parent` and break
+                                                               if ( node.nodeType === 1 && ++diff && node === elem ) {
+                                                                       uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+                                                                       break;
+                                                               }
+                                                       }
+
+                                               } else {
+
+                                                       // Use previously-cached element index if available
+                                                       if ( useCache ) {
+
+                                                               // ...in a gzip-friendly way
+                                                               node = elem;
+                                                               outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+                                                               // Support: IE <9 only
+                                                               // Defend against cloned attroperties (jQuery gh-1709)
+                                                               uniqueCache = outerCache[ node.uniqueID ] ||
+                                                                       ( outerCache[ node.uniqueID ] = {} );
+
+                                                               cache = uniqueCache[ type ] || [];
+                                                               nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+                                                               diff = nodeIndex;
+                                                       }
+
+                                                       // xml :nth-child(...)
+                                                       // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+                                                       if ( diff === false ) {
+
+                                                               // Use the same loop as above to seek `elem` from the start
+                                                               while ( ( node = ++nodeIndex && node && node[ dir ] ||
+                                                                       ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+                                                                       if ( ( ofType ?
+                                                                               node.nodeName.toLowerCase() === name :
+                                                                               node.nodeType === 1 ) &&
+                                                                               ++diff ) {
+
+                                                                               // Cache the index of each encountered element
+                                                                               if ( useCache ) {
+                                                                                       outerCache = node[ expando ] ||
+                                                                                               ( node[ expando ] = {} );
+
+                                                                                       // Support: IE <9 only
+                                                                                       // Defend against cloned attroperties (jQuery gh-1709)
+                                                                                       uniqueCache = outerCache[ node.uniqueID ] ||
+                                                                                               ( outerCache[ node.uniqueID ] = {} );
+
+                                                                                       uniqueCache[ type ] = [ dirruns, diff ];
+                                                                               }
+
+                                                                               if ( node === elem ) {
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+
+                                               // Incorporate the offset, then check against cycle size
+                                               diff -= last;
+                                               return diff === first || ( diff % first === 0 && diff / first >= 0 );
+                                       }
+                               };
+               },
+
+               "PSEUDO": function( pseudo, argument ) {
+
+                       // pseudo-class names are case-insensitive
+                       // http://www.w3.org/TR/selectors/#pseudo-classes
+                       // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+                       // Remember that setFilters inherits from pseudos
+                       var args,
+                               fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+                                       Sizzle.error( "unsupported pseudo: " + pseudo );
+
+                       // The user may use createPseudo to indicate that
+                       // arguments are needed to create the filter function
+                       // just as Sizzle does
+                       if ( fn[ expando ] ) {
+                               return fn( argument );
+                       }
+
+                       // But maintain support for old signatures
+                       if ( fn.length > 1 ) {
+                               args = [ pseudo, pseudo, "", argument ];
+                               return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+                                       markFunction( function( seed, matches ) {
+                                               var idx,
+                                                       matched = fn( seed, argument ),
+                                                       i = matched.length;
+                                               while ( i-- ) {
+                                                       idx = indexOf( seed, matched[ i ] );
+                                                       seed[ idx ] = !( matches[ idx ] = matched[ i ] );
+                                               }
+                                       } ) :
+                                       function( elem ) {
+                                               return fn( elem, 0, args );
+                                       };
+                       }
+
+                       return fn;
+               }
+       },
+
+       pseudos: {
+
+               // Potentially complex pseudos
+               "not": markFunction( function( selector ) {
+
+                       // Trim the selector passed to compile
+                       // to avoid treating leading and trailing
+                       // spaces as combinators
+                       var input = [],
+                               results = [],
+                               matcher = compile( selector.replace( rtrim, "$1" ) );
+
+                       return matcher[ expando ] ?
+                               markFunction( function( seed, matches, _context, xml ) {
+                                       var elem,
+                                               unmatched = matcher( seed, null, xml, [] ),
+                                               i = seed.length;
+
+                                       // Match elements unmatched by `matcher`
+                                       while ( i-- ) {
+                                               if ( ( elem = unmatched[ i ] ) ) {
+                                                       seed[ i ] = !( matches[ i ] = elem );
+                                               }
+                                       }
+                               } ) :
+                               function( elem, _context, xml ) {
+                                       input[ 0 ] = elem;
+                                       matcher( input, null, xml, results );
+
+                                       // Don't keep the element (issue #299)
+                                       input[ 0 ] = null;
+                                       return !results.pop();
+                               };
+               } ),
+
+               "has": markFunction( function( selector ) {
+                       return function( elem ) {
+                               return Sizzle( selector, elem ).length > 0;
+                       };
+               } ),
+
+               "contains": markFunction( function( text ) {
+                       text = text.replace( runescape, funescape );
+                       return function( elem ) {
+                               return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
+                       };
+               } ),
+
+               // "Whether an element is represented by a :lang() selector
+               // is based solely on the element's language value
+               // being equal to the identifier C,
+               // or beginning with the identifier C immediately followed by "-".
+               // The matching of C against the element's language value is performed case-insensitively.
+               // The identifier C does not have to be a valid language name."
+               // http://www.w3.org/TR/selectors/#lang-pseudo
+               "lang": markFunction( function( lang ) {
+
+                       // lang value must be a valid identifier
+                       if ( !ridentifier.test( lang || "" ) ) {
+                               Sizzle.error( "unsupported lang: " + lang );
+                       }
+                       lang = lang.replace( runescape, funescape ).toLowerCase();
+                       return function( elem ) {
+                               var elemLang;
+                               do {
+                                       if ( ( elemLang = documentIsHTML ?
+                                               elem.lang :
+                                               elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
+
+                                               elemLang = elemLang.toLowerCase();
+                                               return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+                                       }
+                               } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
+                               return false;
+                       };
+               } ),
+
+               // Miscellaneous
+               "target": function( elem ) {
+                       var hash = window.location && window.location.hash;
+                       return hash && hash.slice( 1 ) === elem.id;
+               },
+
+               "root": function( elem ) {
+                       return elem === docElem;
+               },
+
+               "focus": function( elem ) {
+                       return elem === document.activeElement &&
+                               ( !document.hasFocus || document.hasFocus() ) &&
+                               !!( elem.type || elem.href || ~elem.tabIndex );
+               },
+
+               // Boolean properties
+               "enabled": createDisabledPseudo( false ),
+               "disabled": createDisabledPseudo( true ),
+
+               "checked": function( elem ) {
+
+                       // In CSS3, :checked should return both checked and selected elements
+                       // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+                       var nodeName = elem.nodeName.toLowerCase();
+                       return ( nodeName === "input" && !!elem.checked ) ||
+                               ( nodeName === "option" && !!elem.selected );
+               },
+
+               "selected": function( elem ) {
+
+                       // Accessing this property makes selected-by-default
+                       // options in Safari work properly
+                       if ( elem.parentNode ) {
+                               // eslint-disable-next-line no-unused-expressions
+                               elem.parentNode.selectedIndex;
+                       }
+
+                       return elem.selected === true;
+               },
+
+               // Contents
+               "empty": function( elem ) {
+
+                       // http://www.w3.org/TR/selectors/#empty-pseudo
+                       // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+                       //   but not by others (comment: 8; processing instruction: 7; etc.)
+                       // nodeType < 6 works because attributes (2) do not appear as children
+                       for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+                               if ( elem.nodeType < 6 ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               },
+
+               "parent": function( elem ) {
+                       return !Expr.pseudos[ "empty" ]( elem );
+               },
+
+               // Element/input types
+               "header": function( elem ) {
+                       return rheader.test( elem.nodeName );
+               },
+
+               "input": function( elem ) {
+                       return rinputs.test( elem.nodeName );
+               },
+
+               "button": function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return name === "input" && elem.type === "button" || name === "button";
+               },
+
+               "text": function( elem ) {
+                       var attr;
+                       return elem.nodeName.toLowerCase() === "input" &&
+                               elem.type === "text" &&
+
+                               // Support: IE<8
+                               // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+                               ( ( attr = elem.getAttribute( "type" ) ) == null ||
+                                       attr.toLowerCase() === "text" );
+               },
+
+               // Position-in-collection
+               "first": createPositionalPseudo( function() {
+                       return [ 0 ];
+               } ),
+
+               "last": createPositionalPseudo( function( _matchIndexes, length ) {
+                       return [ length - 1 ];
+               } ),
+
+               "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
+                       return [ argument < 0 ? argument + length : argument ];
+               } ),
+
+               "even": createPositionalPseudo( function( matchIndexes, length ) {
+                       var i = 0;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               } ),
+
+               "odd": createPositionalPseudo( function( matchIndexes, length ) {
+                       var i = 1;
+                       for ( ; i < length; i += 2 ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               } ),
+
+               "lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ?
+                               argument + length :
+                               argument > length ?
+                                       length :
+                                       argument;
+                       for ( ; --i >= 0; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               } ),
+
+               "gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+                       var i = argument < 0 ? argument + length : argument;
+                       for ( ; ++i < length; ) {
+                               matchIndexes.push( i );
+                       }
+                       return matchIndexes;
+               } )
+       }
+};
+
+Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+       Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+       Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+       var matched, match, tokens, type,
+               soFar, groups, preFilters,
+               cached = tokenCache[ selector + " " ];
+
+       if ( cached ) {
+               return parseOnly ? 0 : cached.slice( 0 );
+       }
+
+       soFar = selector;
+       groups = [];
+       preFilters = Expr.preFilter;
+
+       while ( soFar ) {
+
+               // Comma and first run
+               if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
+                       if ( match ) {
+
+                               // Don't consume trailing commas as valid
+                               soFar = soFar.slice( match[ 0 ].length ) || soFar;
+                       }
+                       groups.push( ( tokens = [] ) );
+               }
+
+               matched = false;
+
+               // Combinators
+               if ( ( match = rcombinators.exec( soFar ) ) ) {
+                       matched = match.shift();
+                       tokens.push( {
+                               value: matched,
+
+                               // Cast descendant combinators to space
+                               type: match[ 0 ].replace( rtrim, " " )
+                       } );
+                       soFar = soFar.slice( matched.length );
+               }
+
+               // Filters
+               for ( type in Expr.filter ) {
+                       if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
+                               ( match = preFilters[ type ]( match ) ) ) ) {
+                               matched = match.shift();
+                               tokens.push( {
+                                       value: matched,
+                                       type: type,
+                                       matches: match
+                               } );
+                               soFar = soFar.slice( matched.length );
+                       }
+               }
+
+               if ( !matched ) {
+                       break;
+               }
+       }
+
+       // Return the length of the invalid excess
+       // if we're just parsing
+       // Otherwise, throw an error or return tokens
+       return parseOnly ?
+               soFar.length :
+               soFar ?
+                       Sizzle.error( selector ) :
+
+                       // Cache the tokens
+                       tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+       var i = 0,
+               len = tokens.length,
+               selector = "";
+       for ( ; i < len; i++ ) {
+               selector += tokens[ i ].value;
+       }
+       return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+       var dir = combinator.dir,
+               skip = combinator.next,
+               key = skip || dir,
+               checkNonElements = base && key === "parentNode",
+               doneName = done++;
+
+       return combinator.first ?
+
+               // Check against closest ancestor/preceding element
+               function( elem, context, xml ) {
+                       while ( ( elem = elem[ dir ] ) ) {
+                               if ( elem.nodeType === 1 || checkNonElements ) {
+                                       return matcher( elem, context, xml );
+                               }
+                       }
+                       return false;
+               } :
+
+               // Check against all ancestor/preceding elements
+               function( elem, context, xml ) {
+                       var oldCache, uniqueCache, outerCache,
+                               newCache = [ dirruns, doneName ];
+
+                       // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
+                       if ( xml ) {
+                               while ( ( elem = elem[ dir ] ) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               if ( matcher( elem, context, xml ) ) {
+                                                       return true;
+                                               }
+                                       }
+                               }
+                       } else {
+                               while ( ( elem = elem[ dir ] ) ) {
+                                       if ( elem.nodeType === 1 || checkNonElements ) {
+                                               outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+
+                                               // Support: IE <9 only
+                                               // Defend against cloned attroperties (jQuery gh-1709)
+                                               uniqueCache = outerCache[ elem.uniqueID ] ||
+                                                       ( outerCache[ elem.uniqueID ] = {} );
+
+                                               if ( skip && skip === elem.nodeName.toLowerCase() ) {
+                                                       elem = elem[ dir ] || elem;
+                                               } else if ( ( oldCache = uniqueCache[ key ] ) &&
+                                                       oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+                                                       // Assign to newCache so results back-propagate to previous elements
+                                                       return ( newCache[ 2 ] = oldCache[ 2 ] );
+                                               } else {
+
+                                                       // Reuse newcache so results back-propagate to previous elements
+                                                       uniqueCache[ key ] = newCache;
+
+                                                       // A match means we're done; a fail means we have to keep checking
+                                                       if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
+                                                               return true;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       return false;
+               };
+}
+
+function elementMatcher( matchers ) {
+       return matchers.length > 1 ?
+               function( elem, context, xml ) {
+                       var i = matchers.length;
+                       while ( i-- ) {
+                               if ( !matchers[ i ]( elem, context, xml ) ) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               } :
+               matchers[ 0 ];
+}
+
+function multipleContexts( selector, contexts, results ) {
+       var i = 0,
+               len = contexts.length;
+       for ( ; i < len; i++ ) {
+               Sizzle( selector, contexts[ i ], results );
+       }
+       return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+       var elem,
+               newUnmatched = [],
+               i = 0,
+               len = unmatched.length,
+               mapped = map != null;
+
+       for ( ; i < len; i++ ) {
+               if ( ( elem = unmatched[ i ] ) ) {
+                       if ( !filter || filter( elem, context, xml ) ) {
+                               newUnmatched.push( elem );
+                               if ( mapped ) {
+                                       map.push( i );
+                               }
+                       }
+               }
+       }
+
+       return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+       if ( postFilter && !postFilter[ expando ] ) {
+               postFilter = setMatcher( postFilter );
+       }
+       if ( postFinder && !postFinder[ expando ] ) {
+               postFinder = setMatcher( postFinder, postSelector );
+       }
+       return markFunction( function( seed, results, context, xml ) {
+               var temp, i, elem,
+                       preMap = [],
+                       postMap = [],
+                       preexisting = results.length,
+
+                       // Get initial elements from seed or context
+                       elems = seed || multipleContexts(
+                               selector || "*",
+                               context.nodeType ? [ context ] : context,
+                               []
+                       ),
+
+                       // Prefilter to get matcher input, preserving a map for seed-results synchronization
+                       matcherIn = preFilter && ( seed || !selector ) ?
+                               condense( elems, preMap, preFilter, context, xml ) :
+                               elems,
+
+                       matcherOut = matcher ?
+
+                               // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+                               postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+                                       // ...intermediate processing is necessary
+                                       [] :
+
+                                       // ...otherwise use results directly
+                                       results :
+                               matcherIn;
+
+               // Find primary matches
+               if ( matcher ) {
+                       matcher( matcherIn, matcherOut, context, xml );
+               }
+
+               // Apply postFilter
+               if ( postFilter ) {
+                       temp = condense( matcherOut, postMap );
+                       postFilter( temp, [], context, xml );
+
+                       // Un-match failing elements by moving them back to matcherIn
+                       i = temp.length;
+                       while ( i-- ) {
+                               if ( ( elem = temp[ i ] ) ) {
+                                       matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
+                               }
+                       }
+               }
+
+               if ( seed ) {
+                       if ( postFinder || preFilter ) {
+                               if ( postFinder ) {
+
+                                       // Get the final matcherOut by condensing this intermediate into postFinder contexts
+                                       temp = [];
+                                       i = matcherOut.length;
+                                       while ( i-- ) {
+                                               if ( ( elem = matcherOut[ i ] ) ) {
+
+                                                       // Restore matcherIn since elem is not yet a final match
+                                                       temp.push( ( matcherIn[ i ] = elem ) );
+                                               }
+                                       }
+                                       postFinder( null, ( matcherOut = [] ), temp, xml );
+                               }
+
+                               // Move matched elements from seed to results to keep them synchronized
+                               i = matcherOut.length;
+                               while ( i-- ) {
+                                       if ( ( elem = matcherOut[ i ] ) &&
+                                               ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
+
+                                               seed[ temp ] = !( results[ temp ] = elem );
+                                       }
+                               }
+                       }
+
+               // Add elements to results, through postFinder if defined
+               } else {
+                       matcherOut = condense(
+                               matcherOut === results ?
+                                       matcherOut.splice( preexisting, matcherOut.length ) :
+                                       matcherOut
+                       );
+                       if ( postFinder ) {
+                               postFinder( null, results, matcherOut, xml );
+                       } else {
+                               push.apply( results, matcherOut );
+                       }
+               }
+       } );
+}
+
+function matcherFromTokens( tokens ) {
+       var checkContext, matcher, j,
+               len = tokens.length,
+               leadingRelative = Expr.relative[ tokens[ 0 ].type ],
+               implicitRelative = leadingRelative || Expr.relative[ " " ],
+               i = leadingRelative ? 1 : 0,
+
+               // The foundational matcher ensures that elements are reachable from top-level context(s)
+               matchContext = addCombinator( function( elem ) {
+                       return elem === checkContext;
+               }, implicitRelative, true ),
+               matchAnyContext = addCombinator( function( elem ) {
+                       return indexOf( checkContext, elem ) > -1;
+               }, implicitRelative, true ),
+               matchers = [ function( elem, context, xml ) {
+                       var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+                               ( checkContext = context ).nodeType ?
+                                       matchContext( elem, context, xml ) :
+                                       matchAnyContext( elem, context, xml ) );
+
+                       // Avoid hanging onto element (issue #299)
+                       checkContext = null;
+                       return ret;
+               } ];
+
+       for ( ; i < len; i++ ) {
+               if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+                       matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+               } else {
+                       matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
+
+                       // Return special upon seeing a positional matcher
+                       if ( matcher[ expando ] ) {
+
+                               // Find the next relative operator (if any) for proper handling
+                               j = ++i;
+                               for ( ; j < len; j++ ) {
+                                       if ( Expr.relative[ tokens[ j ].type ] ) {
+                                               break;
+                                       }
+                               }
+                               return setMatcher(
+                                       i > 1 && elementMatcher( matchers ),
+                                       i > 1 && toSelector(
+
+                                       // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+                                       tokens
+                                               .slice( 0, i - 1 )
+                                               .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
+                                       ).replace( rtrim, "$1" ),
+                                       matcher,
+                                       i < j && matcherFromTokens( tokens.slice( i, j ) ),
+                                       j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
+                                       j < len && toSelector( tokens )
+                               );
+                       }
+                       matchers.push( matcher );
+               }
+       }
+
+       return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+       var bySet = setMatchers.length > 0,
+               byElement = elementMatchers.length > 0,
+               superMatcher = function( seed, context, xml, results, outermost ) {
+                       var elem, j, matcher,
+                               matchedCount = 0,
+                               i = "0",
+                               unmatched = seed && [],
+                               setMatched = [],
+                               contextBackup = outermostContext,
+
+                               // We must always have either seed elements or outermost context
+                               elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+
+                               // Use integer dirruns iff this is the outermost matcher
+                               dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
+                               len = elems.length;
+
+                       if ( outermost ) {
+
+                               // Support: IE 11+, Edge 17 - 18+
+                               // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                               // two documents; shallow comparisons work.
+                               // eslint-disable-next-line eqeqeq
+                               outermostContext = context == document || context || outermost;
+                       }
+
+                       // Add elements passing elementMatchers directly to results
+                       // Support: IE<9, Safari
+                       // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+                       for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
+                               if ( byElement && elem ) {
+                                       j = 0;
+
+                                       // Support: IE 11+, Edge 17 - 18+
+                                       // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+                                       // two documents; shallow comparisons work.
+                                       // eslint-disable-next-line eqeqeq
+                                       if ( !context && elem.ownerDocument != document ) {
+                                               setDocument( elem );
+                                               xml = !documentIsHTML;
+                                       }
+                                       while ( ( matcher = elementMatchers[ j++ ] ) ) {
+                                               if ( matcher( elem, context || document, xml ) ) {
+                                                       results.push( elem );
+                                                       break;
+                                               }
+                                       }
+                                       if ( outermost ) {
+                                               dirruns = dirrunsUnique;
+                                       }
+                               }
+
+                               // Track unmatched elements for set filters
+                               if ( bySet ) {
+
+                                       // They will have gone through all possible matchers
+                                       if ( ( elem = !matcher && elem ) ) {
+                                               matchedCount--;
+                                       }
+
+                                       // Lengthen the array for every element, matched or not
+                                       if ( seed ) {
+                                               unmatched.push( elem );
+                                       }
+                               }
+                       }
+
+                       // `i` is now the count of elements visited above, and adding it to `matchedCount`
+                       // makes the latter nonnegative.
+                       matchedCount += i;
+
+                       // Apply set filters to unmatched elements
+                       // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+                       // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+                       // no element matchers and no seed.
+                       // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+                       // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+                       // numerically zero.
+                       if ( bySet && i !== matchedCount ) {
+                               j = 0;
+                               while ( ( matcher = setMatchers[ j++ ] ) ) {
+                                       matcher( unmatched, setMatched, context, xml );
+                               }
+
+                               if ( seed ) {
+
+                                       // Reintegrate element matches to eliminate the need for sorting
+                                       if ( matchedCount > 0 ) {
+                                               while ( i-- ) {
+                                                       if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
+                                                               setMatched[ i ] = pop.call( results );
+                                                       }
+                                               }
+                                       }
+
+                                       // Discard index placeholder values to get only actual matches
+                                       setMatched = condense( setMatched );
+                               }
+
+                               // Add matches to results
+                               push.apply( results, setMatched );
+
+                               // Seedless set matches succeeding multiple successful matchers stipulate sorting
+                               if ( outermost && !seed && setMatched.length > 0 &&
+                                       ( matchedCount + setMatchers.length ) > 1 ) {
+
+                                       Sizzle.uniqueSort( results );
+                               }
+                       }
+
+                       // Override manipulation of globals by nested matchers
+                       if ( outermost ) {
+                               dirruns = dirrunsUnique;
+                               outermostContext = contextBackup;
+                       }
+
+                       return unmatched;
+               };
+
+       return bySet ?
+               markFunction( superMatcher ) :
+               superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+       var i,
+               setMatchers = [],
+               elementMatchers = [],
+               cached = compilerCache[ selector + " " ];
+
+       if ( !cached ) {
+
+               // Generate a function of recursive functions that can be used to check each element
+               if ( !match ) {
+                       match = tokenize( selector );
+               }
+               i = match.length;
+               while ( i-- ) {
+                       cached = matcherFromTokens( match[ i ] );
+                       if ( cached[ expando ] ) {
+                               setMatchers.push( cached );
+                       } else {
+                               elementMatchers.push( cached );
+                       }
+               }
+
+               // Cache the compiled function
+               cached = compilerCache(
+                       selector,
+                       matcherFromGroupMatchers( elementMatchers, setMatchers )
+               );
+
+               // Save selector and tokenization
+               cached.selector = selector;
+       }
+       return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ *  selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ *  selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+       var i, tokens, token, type, find,
+               compiled = typeof selector === "function" && selector,
+               match = !seed && tokenize( ( selector = compiled.selector || selector ) );
+
+       results = results || [];
+
+       // Try to minimize operations if there is only one selector in the list and no seed
+       // (the latter of which guarantees us context)
+       if ( match.length === 1 ) {
+
+               // Reduce context if the leading compound selector is an ID
+               tokens = match[ 0 ] = match[ 0 ].slice( 0 );
+               if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
+                       context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+
+                       context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
+                               .replace( runescape, funescape ), context ) || [] )[ 0 ];
+                       if ( !context ) {
+                               return results;
+
+                       // Precompiled matchers will still verify ancestry, so step up a level
+                       } else if ( compiled ) {
+                               context = context.parentNode;
+                       }
+
+                       selector = selector.slice( tokens.shift().value.length );
+               }
+
+               // Fetch a seed set for right-to-left matching
+               i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
+               while ( i-- ) {
+                       token = tokens[ i ];
+
+                       // Abort if we hit a combinator
+                       if ( Expr.relative[ ( type = token.type ) ] ) {
+                               break;
+                       }
+                       if ( ( find = Expr.find[ type ] ) ) {
+
+                               // Search, expanding context for leading sibling combinators
+                               if ( ( seed = find(
+                                       token.matches[ 0 ].replace( runescape, funescape ),
+                                       rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
+                                               context
+                               ) ) ) {
+
+                                       // If seed is empty or no tokens remain, we can return early
+                                       tokens.splice( i, 1 );
+                                       selector = seed.length && toSelector( tokens );
+                                       if ( !selector ) {
+                                               push.apply( results, seed );
+                                               return results;
+                                       }
+
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       // Compile and execute a filtering function if one is not provided
+       // Provide `match` to avoid retokenization if we modified the selector above
+       ( compiled || compile( selector, match ) )(
+               seed,
+               context,
+               !documentIsHTML,
+               results,
+               !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+       );
+       return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert( function( el ) {
+
+       // Should return 1, but returns 4 (following)
+       return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
+} );
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert( function( el ) {
+       el.innerHTML = "<a href='#'></a>";
+       return el.firstChild.getAttribute( "href" ) === "#";
+} ) ) {
+       addHandle( "type|href|height|width", function( elem, name, isXML ) {
+               if ( !isXML ) {
+                       return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+               }
+       } );
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert( function( el ) {
+       el.innerHTML = "<input/>";
+       el.firstChild.setAttribute( "value", "" );
+       return el.firstChild.getAttribute( "value" ) === "";
+} ) ) {
+       addHandle( "value", function( elem, _name, isXML ) {
+               if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+                       return elem.defaultValue;
+               }
+       } );
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert( function( el ) {
+       return el.getAttribute( "disabled" ) == null;
+} ) ) {
+       addHandle( booleans, function( elem, name, isXML ) {
+               var val;
+               if ( !isXML ) {
+                       return elem[ name ] === true ? name.toLowerCase() :
+                               ( val = elem.getAttributeNode( name ) ) && val.specified ?
+                                       val.value :
+                                       null;
+               }
+       } );
+}
+
+return Sizzle;
+
+} )( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+
+// Deprecated
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+jQuery.escapeSelector = Sizzle.escape;
+
+
+
+
+var dir = function( elem, dir, until ) {
+       var matched = [],
+               truncate = until !== undefined;
+
+       while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+               if ( elem.nodeType === 1 ) {
+                       if ( truncate && jQuery( elem ).is( until ) ) {
+                               break;
+                       }
+                       matched.push( elem );
+               }
+       }
+       return matched;
+};
+
+
+var siblings = function( n, elem ) {
+       var matched = [];
+
+       for ( ; n; n = n.nextSibling ) {
+               if ( n.nodeType === 1 && n !== elem ) {
+                       matched.push( n );
+               }
+       }
+
+       return matched;
+};
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+
+
+function nodeName( elem, name ) {
+
+  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+
+};
+var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
+
+
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+       if ( isFunction( qualifier ) ) {
+               return jQuery.grep( elements, function( elem, i ) {
+                       return !!qualifier.call( elem, i, elem ) !== not;
+               } );
+       }
+
+       // Single element
+       if ( qualifier.nodeType ) {
+               return jQuery.grep( elements, function( elem ) {
+                       return ( elem === qualifier ) !== not;
+               } );
+       }
+
+       // Arraylike of elements (jQuery, arguments, Array)
+       if ( typeof qualifier !== "string" ) {
+               return jQuery.grep( elements, function( elem ) {
+                       return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
+               } );
+       }
+
+       // Filtered directly for both simple and complex selectors
+       return jQuery.filter( qualifier, elements, not );
+}
+
+jQuery.filter = function( expr, elems, not ) {
+       var elem = elems[ 0 ];
+
+       if ( not ) {
+               expr = ":not(" + expr + ")";
+       }
+
+       if ( elems.length === 1 && elem.nodeType === 1 ) {
+               return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
+       }
+
+       return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+               return elem.nodeType === 1;
+       } ) );
+};
+
+jQuery.fn.extend( {
+       find: function( selector ) {
+               var i, ret,
+                       len = this.length,
+                       self = this;
+
+               if ( typeof selector !== "string" ) {
+                       return this.pushStack( jQuery( selector ).filter( function() {
+                               for ( i = 0; i < len; i++ ) {
+                                       if ( jQuery.contains( self[ i ], this ) ) {
+                                               return true;
+                                       }
+                               }
+                       } ) );
+               }
+
+               ret = this.pushStack( [] );
+
+               for ( i = 0; i < len; i++ ) {
+                       jQuery.find( selector, self[ i ], ret );
+               }
+
+               return len > 1 ? jQuery.uniqueSort( ret ) : ret;
+       },
+       filter: function( selector ) {
+               return this.pushStack( winnow( this, selector || [], false ) );
+       },
+       not: function( selector ) {
+               return this.pushStack( winnow( this, selector || [], true ) );
+       },
+       is: function( selector ) {
+               return !!winnow(
+                       this,
+
+                       // If this is a positional/relative selector, check membership in the returned set
+                       // so $("p:first").is("p:last") won't return true for a doc with two "p".
+                       typeof selector === "string" && rneedsContext.test( selector ) ?
+                               jQuery( selector ) :
+                               selector || [],
+                       false
+               ).length;
+       }
+} );
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+       // A simple way to check for HTML strings
+       // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+       // Strict HTML recognition (#11290: must start with <)
+       // Shortcut simple #id case for speed
+       rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
+
+       init = jQuery.fn.init = function( selector, context, root ) {
+               var match, elem;
+
+               // HANDLE: $(""), $(null), $(undefined), $(false)
+               if ( !selector ) {
+                       return this;
+               }
+
+               // Method init() accepts an alternate rootjQuery
+               // so migrate can support jQuery.sub (gh-2101)
+               root = root || rootjQuery;
+
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       if ( selector[ 0 ] === "<" &&
+                               selector[ selector.length - 1 ] === ">" &&
+                               selector.length >= 3 ) {
+
+                               // Assume that strings that start and end with <> are HTML and skip the regex check
+                               match = [ null, selector, null ];
+
+                       } else {
+                               match = rquickExpr.exec( selector );
+                       }
+
+                       // Match html or make sure no context is specified for #id
+                       if ( match && ( match[ 1 ] || !context ) ) {
+
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[ 1 ] ) {
+                                       context = context instanceof jQuery ? context[ 0 ] : context;
+
+                                       // Option to run scripts is true for back-compat
+                                       // Intentionally let the error be thrown if parseHTML is not present
+                                       jQuery.merge( this, jQuery.parseHTML(
+                                               match[ 1 ],
+                                               context && context.nodeType ? context.ownerDocument || context : document,
+                                               true
+                                       ) );
+
+                                       // HANDLE: $(html, props)
+                                       if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
+                                               for ( match in context ) {
+
+                                                       // Properties of context are called as methods if possible
+                                                       if ( isFunction( this[ match ] ) ) {
+                                                               this[ match ]( context[ match ] );
+
+                                                       // ...and otherwise set as attributes
+                                                       } else {
+                                                               this.attr( match, context[ match ] );
+                                                       }
+                                               }
+                                       }
+
+                                       return this;
+
+                               // HANDLE: $(#id)
+                               } else {
+                                       elem = document.getElementById( match[ 2 ] );
+
+                                       if ( elem ) {
+
+                                               // Inject the element directly into the jQuery object
+                                               this[ 0 ] = elem;
+                                               this.length = 1;
+                                       }
+                                       return this;
+                               }
+
+                       // HANDLE: $(expr, $(...))
+                       } else if ( !context || context.jquery ) {
+                               return ( context || root ).find( selector );
+
+                       // HANDLE: $(expr, context)
+                       // (which is just equivalent to: $(context).find(expr)
+                       } else {
+                               return this.constructor( context ).find( selector );
+                       }
+
+               // HANDLE: $(DOMElement)
+               } else if ( selector.nodeType ) {
+                       this[ 0 ] = selector;
+                       this.length = 1;
+                       return this;
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( isFunction( selector ) ) {
+                       return root.ready !== undefined ?
+                               root.ready( selector ) :
+
+                               // Execute immediately if ready is not present
+                               selector( jQuery );
+               }
+
+               return jQuery.makeArray( selector, this );
+       };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+       // Methods guaranteed to produce a unique set when starting from a unique set
+       guaranteedUnique = {
+               children: true,
+               contents: true,
+               next: true,
+               prev: true
+       };
+
+jQuery.fn.extend( {
+       has: function( target ) {
+               var targets = jQuery( target, this ),
+                       l = targets.length;
+
+               return this.filter( function() {
+                       var i = 0;
+                       for ( ; i < l; i++ ) {
+                               if ( jQuery.contains( this, targets[ i ] ) ) {
+                                       return true;
+                               }
+                       }
+               } );
+       },
+
+       closest: function( selectors, context ) {
+               var cur,
+                       i = 0,
+                       l = this.length,
+                       matched = [],
+                       targets = typeof selectors !== "string" && jQuery( selectors );
+
+               // Positional selectors never match, since there's no _selection_ context
+               if ( !rneedsContext.test( selectors ) ) {
+                       for ( ; i < l; i++ ) {
+                               for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
+
+                                       // Always skip document fragments
+                                       if ( cur.nodeType < 11 && ( targets ?
+                                               targets.index( cur ) > -1 :
+
+                                               // Don't pass non-elements to Sizzle
+                                               cur.nodeType === 1 &&
+                                                       jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+                                               matched.push( cur );
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+       },
+
+       // Determine the position of an element within the set
+       index: function( elem ) {
+
+               // No argument, return index in parent
+               if ( !elem ) {
+                       return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+               }
+
+               // Index in selector
+               if ( typeof elem === "string" ) {
+                       return indexOf.call( jQuery( elem ), this[ 0 ] );
+               }
+
+               // Locate the position of the desired element
+               return indexOf.call( this,
+
+                       // If it receives a jQuery object, the first element is used
+                       elem.jquery ? elem[ 0 ] : elem
+               );
+       },
+
+       add: function( selector, context ) {
+               return this.pushStack(
+                       jQuery.uniqueSort(
+                               jQuery.merge( this.get(), jQuery( selector, context ) )
+                       )
+               );
+       },
+
+       addBack: function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter( selector )
+               );
+       }
+} );
+
+function sibling( cur, dir ) {
+       while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
+       return cur;
+}
+
+jQuery.each( {
+       parent: function( elem ) {
+               var parent = elem.parentNode;
+               return parent && parent.nodeType !== 11 ? parent : null;
+       },
+       parents: function( elem ) {
+               return dir( elem, "parentNode" );
+       },
+       parentsUntil: function( elem, _i, until ) {
+               return dir( elem, "parentNode", until );
+       },
+       next: function( elem ) {
+               return sibling( elem, "nextSibling" );
+       },
+       prev: function( elem ) {
+               return sibling( elem, "previousSibling" );
+       },
+       nextAll: function( elem ) {
+               return dir( elem, "nextSibling" );
+       },
+       prevAll: function( elem ) {
+               return dir( elem, "previousSibling" );
+       },
+       nextUntil: function( elem, _i, until ) {
+               return dir( elem, "nextSibling", until );
+       },
+       prevUntil: function( elem, _i, until ) {
+               return dir( elem, "previousSibling", until );
+       },
+       siblings: function( elem ) {
+               return siblings( ( elem.parentNode || {} ).firstChild, elem );
+       },
+       children: function( elem ) {
+               return siblings( elem.firstChild );
+       },
+       contents: function( elem ) {
+               if ( elem.contentDocument != null &&
+
+                       // Support: IE 11+
+                       // <object> elements with no `data` attribute has an object
+                       // `contentDocument` with a `null` prototype.
+                       getProto( elem.contentDocument ) ) {
+
+                       return elem.contentDocument;
+               }
+
+               // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
+               // Treat the template element as a regular one in browsers that
+               // don't support it.
+               if ( nodeName( elem, "template" ) ) {
+                       elem = elem.content || elem;
+               }
+
+               return jQuery.merge( [], elem.childNodes );
+       }
+}, function( name, fn ) {
+       jQuery.fn[ name ] = function( until, selector ) {
+               var matched = jQuery.map( this, fn, until );
+
+               if ( name.slice( -5 ) !== "Until" ) {
+                       selector = until;
+               }
+
+               if ( selector && typeof selector === "string" ) {
+                       matched = jQuery.filter( selector, matched );
+               }
+
+               if ( this.length > 1 ) {
+
+                       // Remove duplicates
+                       if ( !guaranteedUnique[ name ] ) {
+                               jQuery.uniqueSort( matched );
+                       }
+
+                       // Reverse order for parents* and prev-derivatives
+                       if ( rparentsprev.test( name ) ) {
+                               matched.reverse();
+                       }
+               }
+
+               return this.pushStack( matched );
+       };
+} );
+var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
+
+
+
+// Convert String-formatted options into Object-formatted ones
+function createOptions( options ) {
+       var object = {};
+       jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
+               object[ flag ] = true;
+       } );
+       return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ *     options: an optional list of space-separated options that will change how
+ *                     the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ *     once:                   will ensure the callback list can only be fired once (like a Deferred)
+ *
+ *     memory:                 will keep track of previous values and will call any callback added
+ *                                     after the list has been fired right away with the latest "memorized"
+ *                                     values (like a Deferred)
+ *
+ *     unique:                 will ensure a callback can only be added once (no duplicate in the list)
+ *
+ *     stopOnFalse:    interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+       // Convert options from String-formatted to Object-formatted if needed
+       // (we check in cache first)
+       options = typeof options === "string" ?
+               createOptions( options ) :
+               jQuery.extend( {}, options );
+
+       var // Flag to know if list is currently firing
+               firing,
+
+               // Last fire value for non-forgettable lists
+               memory,
+
+               // Flag to know if list was already fired
+               fired,
+
+               // Flag to prevent firing
+               locked,
+
+               // Actual callback list
+               list = [],
+
+               // Queue of execution data for repeatable lists
+               queue = [],
+
+               // Index of currently firing callback (modified by add/remove as needed)
+               firingIndex = -1,
+
+               // Fire callbacks
+               fire = function() {
+
+                       // Enforce single-firing
+                       locked = locked || options.once;
+
+                       // Execute callbacks for all pending executions,
+                       // respecting firingIndex overrides and runtime changes
+                       fired = firing = true;
+                       for ( ; queue.length; firingIndex = -1 ) {
+                               memory = queue.shift();
+                               while ( ++firingIndex < list.length ) {
+
+                                       // Run callback and check for early termination
+                                       if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+                                               options.stopOnFalse ) {
+
+                                               // Jump to end and forget the data so .add doesn't re-fire
+                                               firingIndex = list.length;
+                                               memory = false;
+                                       }
+                               }
+                       }
+
+                       // Forget the data if we're done with it
+                       if ( !options.memory ) {
+                               memory = false;
+                       }
+
+                       firing = false;
+
+                       // Clean up if we're done firing for good
+                       if ( locked ) {
+
+                               // Keep an empty list if we have data for future add calls
+                               if ( memory ) {
+                                       list = [];
+
+                               // Otherwise, this object is spent
+                               } else {
+                                       list = "";
+                               }
+                       }
+               },
+
+               // Actual Callbacks object
+               self = {
+
+                       // Add a callback or a collection of callbacks to the list
+                       add: function() {
+                               if ( list ) {
+
+                                       // If we have memory from a past run, we should fire after adding
+                                       if ( memory && !firing ) {
+                                               firingIndex = list.length - 1;
+                                               queue.push( memory );
+                                       }
+
+                                       ( function add( args ) {
+                                               jQuery.each( args, function( _, arg ) {
+                                                       if ( isFunction( arg ) ) {
+                                                               if ( !options.unique || !self.has( arg ) ) {
+                                                                       list.push( arg );
+                                                               }
+                                                       } else if ( arg && arg.length && toType( arg ) !== "string" ) {
+
+                                                               // Inspect recursively
+                                                               add( arg );
+                                                       }
+                                               } );
+                                       } )( arguments );
+
+                                       if ( memory && !firing ) {
+                                               fire();
+                                       }
+                               }
+                               return this;
+                       },
+
+                       // Remove a callback from the list
+                       remove: function() {
+                               jQuery.each( arguments, function( _, arg ) {
+                                       var index;
+                                       while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+                                               list.splice( index, 1 );
+
+                                               // Handle firing indexes
+                                               if ( index <= firingIndex ) {
+                                                       firingIndex--;
+                                               }
+                                       }
+                               } );
+                               return this;
+                       },
+
+                       // Check if a given callback is in the list.
+                       // If no argument is given, return whether or not list has callbacks attached.
+                       has: function( fn ) {
+                               return fn ?
+                                       jQuery.inArray( fn, list ) > -1 :
+                                       list.length > 0;
+                       },
+
+                       // Remove all callbacks from the list
+                       empty: function() {
+                               if ( list ) {
+                                       list = [];
+                               }
+                               return this;
+                       },
+
+                       // Disable .fire and .add
+                       // Abort any current/pending executions
+                       // Clear all callbacks and values
+                       disable: function() {
+                               locked = queue = [];
+                               list = memory = "";
+                               return this;
+                       },
+                       disabled: function() {
+                               return !list;
+                       },
+
+                       // Disable .fire
+                       // Also disable .add unless we have memory (since it would have no effect)
+                       // Abort any pending executions
+                       lock: function() {
+                               locked = queue = [];
+                               if ( !memory && !firing ) {
+                                       list = memory = "";
+                               }
+                               return this;
+                       },
+                       locked: function() {
+                               return !!locked;
+                       },
+
+                       // Call all callbacks with the given context and arguments
+                       fireWith: function( context, args ) {
+                               if ( !locked ) {
+                                       args = args || [];
+                                       args = [ context, args.slice ? args.slice() : args ];
+                                       queue.push( args );
+                                       if ( !firing ) {
+                                               fire();
+                                       }
+                               }
+                               return this;
+                       },
+
+                       // Call all the callbacks with the given arguments
+                       fire: function() {
+                               self.fireWith( this, arguments );
+                               return this;
+                       },
+
+                       // To know if the callbacks have already been called at least once
+                       fired: function() {
+                               return !!fired;
+                       }
+               };
+
+       return self;
+};
+
+
+function Identity( v ) {
+       return v;
+}
+function Thrower( ex ) {
+       throw ex;
+}
+
+function adoptValue( value, resolve, reject, noValue ) {
+       var method;
+
+       try {
+
+               // Check for promise aspect first to privilege synchronous behavior
+               if ( value && isFunction( ( method = value.promise ) ) ) {
+                       method.call( value ).done( resolve ).fail( reject );
+
+               // Other thenables
+               } else if ( value && isFunction( ( method = value.then ) ) ) {
+                       method.call( value, resolve, reject );
+
+               // Other non-thenables
+               } else {
+
+                       // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
+                       // * false: [ value ].slice( 0 ) => resolve( value )
+                       // * true: [ value ].slice( 1 ) => resolve()
+                       resolve.apply( undefined, [ value ].slice( noValue ) );
+               }
+
+       // For Promises/A+, convert exceptions into rejections
+       // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+       // Deferred#then to conditionally suppress rejection.
+       } catch ( value ) {
+
+               // Support: Android 4.0 only
+               // Strict mode functions invoked without .call/.apply get global-object context
+               reject.apply( undefined, [ value ] );
+       }
+}
+
+jQuery.extend( {
+
+       Deferred: function( func ) {
+               var tuples = [
+
+                               // action, add listener, callbacks,
+                               // ... .then handlers, argument index, [final state]
+                               [ "notify", "progress", jQuery.Callbacks( "memory" ),
+                                       jQuery.Callbacks( "memory" ), 2 ],
+                               [ "resolve", "done", jQuery.Callbacks( "once memory" ),
+                                       jQuery.Callbacks( "once memory" ), 0, "resolved" ],
+                               [ "reject", "fail", jQuery.Callbacks( "once memory" ),
+                                       jQuery.Callbacks( "once memory" ), 1, "rejected" ]
+                       ],
+                       state = "pending",
+                       promise = {
+                               state: function() {
+                                       return state;
+                               },
+                               always: function() {
+                                       deferred.done( arguments ).fail( arguments );
+                                       return this;
+                               },
+                               "catch": function( fn ) {
+                                       return promise.then( null, fn );
+                               },
+
+                               // Keep pipe for back-compat
+                               pipe: function( /* fnDone, fnFail, fnProgress */ ) {
+                                       var fns = arguments;
+
+                                       return jQuery.Deferred( function( newDefer ) {
+                                               jQuery.each( tuples, function( _i, tuple ) {
+
+                                                       // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+                                                       var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+                                                       // deferred.progress(function() { bind to newDefer or newDefer.notify })
+                                                       // deferred.done(function() { bind to newDefer or newDefer.resolve })
+                                                       // deferred.fail(function() { bind to newDefer or newDefer.reject })
+                                                       deferred[ tuple[ 1 ] ]( function() {
+                                                               var returned = fn && fn.apply( this, arguments );
+                                                               if ( returned && isFunction( returned.promise ) ) {
+                                                                       returned.promise()
+                                                                               .progress( newDefer.notify )
+                                                                               .done( newDefer.resolve )
+                                                                               .fail( newDefer.reject );
+                                                               } else {
+                                                                       newDefer[ tuple[ 0 ] + "With" ](
+                                                                               this,
+                                                                               fn ? [ returned ] : arguments
+                                                                       );
+                                                               }
+                                                       } );
+                                               } );
+                                               fns = null;
+                                       } ).promise();
+                               },
+                               then: function( onFulfilled, onRejected, onProgress ) {
+                                       var maxDepth = 0;
+                                       function resolve( depth, deferred, handler, special ) {
+                                               return function() {
+                                                       var that = this,
+                                                               args = arguments,
+                                                               mightThrow = function() {
+                                                                       var returned, then;
+
+                                                                       // Support: Promises/A+ section 2.3.3.3.3
+                                                                       // https://promisesaplus.com/#point-59
+                                                                       // Ignore double-resolution attempts
+                                                                       if ( depth < maxDepth ) {
+                                                                               return;
+                                                                       }
+
+                                                                       returned = handler.apply( that, args );
+
+                                                                       // Support: Promises/A+ section 2.3.1
+                                                                       // https://promisesaplus.com/#point-48
+                                                                       if ( returned === deferred.promise() ) {
+                                                                               throw new TypeError( "Thenable self-resolution" );
+                                                                       }
+
+                                                                       // Support: Promises/A+ sections 2.3.3.1, 3.5
+                                                                       // https://promisesaplus.com/#point-54
+                                                                       // https://promisesaplus.com/#point-75
+                                                                       // Retrieve `then` only once
+                                                                       then = returned &&
+
+                                                                               // Support: Promises/A+ section 2.3.4
+                                                                               // https://promisesaplus.com/#point-64
+                                                                               // Only check objects and functions for thenability
+                                                                               ( typeof returned === "object" ||
+                                                                                       typeof returned === "function" ) &&
+                                                                               returned.then;
+
+                                                                       // Handle a returned thenable
+                                                                       if ( isFunction( then ) ) {
+
+                                                                               // Special processors (notify) just wait for resolution
+                                                                               if ( special ) {
+                                                                                       then.call(
+                                                                                               returned,
+                                                                                               resolve( maxDepth, deferred, Identity, special ),
+                                                                                               resolve( maxDepth, deferred, Thrower, special )
+                                                                                       );
+
+                                                                               // Normal processors (resolve) also hook into progress
+                                                                               } else {
+
+                                                                                       // ...and disregard older resolution values
+                                                                                       maxDepth++;
+
+                                                                                       then.call(
+                                                                                               returned,
+                                                                                               resolve( maxDepth, deferred, Identity, special ),
+                                                                                               resolve( maxDepth, deferred, Thrower, special ),
+                                                                                               resolve( maxDepth, deferred, Identity,
+                                                                                                       deferred.notifyWith )
+                                                                                       );
+                                                                               }
+
+                                                                       // Handle all other returned values
+                                                                       } else {
+
+                                                                               // Only substitute handlers pass on context
+                                                                               // and multiple values (non-spec behavior)
+                                                                               if ( handler !== Identity ) {
+                                                                                       that = undefined;
+                                                                                       args = [ returned ];
+                                                                               }
+
+                                                                               // Process the value(s)
+                                                                               // Default process is resolve
+                                                                               ( special || deferred.resolveWith )( that, args );
+                                                                       }
+                                                               },
+
+                                                               // Only normal processors (resolve) catch and reject exceptions
+                                                               process = special ?
+                                                                       mightThrow :
+                                                                       function() {
+                                                                               try {
+                                                                                       mightThrow();
+                                                                               } catch ( e ) {
+
+                                                                                       if ( jQuery.Deferred.exceptionHook ) {
+                                                                                               jQuery.Deferred.exceptionHook( e,
+                                                                                                       process.stackTrace );
+                                                                                       }
+
+                                                                                       // Support: Promises/A+ section 2.3.3.3.4.1
+                                                                                       // https://promisesaplus.com/#point-61
+                                                                                       // Ignore post-resolution exceptions
+                                                                                       if ( depth + 1 >= maxDepth ) {
+
+                                                                                               // Only substitute handlers pass on context
+                                                                                               // and multiple values (non-spec behavior)
+                                                                                               if ( handler !== Thrower ) {
+                                                                                                       that = undefined;
+                                                                                                       args = [ e ];
+                                                                                               }
+
+                                                                                               deferred.rejectWith( that, args );
+                                                                                       }
+                                                                               }
+                                                                       };
+
+                                                       // Support: Promises/A+ section 2.3.3.3.1
+                                                       // https://promisesaplus.com/#point-57
+                                                       // Re-resolve promises immediately to dodge false rejection from
+                                                       // subsequent errors
+                                                       if ( depth ) {
+                                                               process();
+                                                       } else {
+
+                                                               // Call an optional hook to record the stack, in case of exception
+                                                               // since it's otherwise lost when execution goes async
+                                                               if ( jQuery.Deferred.getStackHook ) {
+                                                                       process.stackTrace = jQuery.Deferred.getStackHook();
+                                                               }
+                                                               window.setTimeout( process );
+                                                       }
+                                               };
+                                       }
+
+                                       return jQuery.Deferred( function( newDefer ) {
+
+                                               // progress_handlers.add( ... )
+                                               tuples[ 0 ][ 3 ].add(
+                                                       resolve(
+                                                               0,
+                                                               newDefer,
+                                                               isFunction( onProgress ) ?
+                                                                       onProgress :
+                                                                       Identity,
+                                                               newDefer.notifyWith
+                                                       )
+                                               );
+
+                                               // fulfilled_handlers.add( ... )
+                                               tuples[ 1 ][ 3 ].add(
+                                                       resolve(
+                                                               0,
+                                                               newDefer,
+                                                               isFunction( onFulfilled ) ?
+                                                                       onFulfilled :
+                                                                       Identity
+                                                       )
+                                               );
+
+                                               // rejected_handlers.add( ... )
+                                               tuples[ 2 ][ 3 ].add(
+                                                       resolve(
+                                                               0,
+                                                               newDefer,
+                                                               isFunction( onRejected ) ?
+                                                                       onRejected :
+                                                                       Thrower
+                                                       )
+                                               );
+                                       } ).promise();
+                               },
+
+                               // Get a promise for this deferred
+                               // If obj is provided, the promise aspect is added to the object
+                               promise: function( obj ) {
+                                       return obj != null ? jQuery.extend( obj, promise ) : promise;
+                               }
+                       },
+                       deferred = {};
+
+               // Add list-specific methods
+               jQuery.each( tuples, function( i, tuple ) {
+                       var list = tuple[ 2 ],
+                               stateString = tuple[ 5 ];
+
+                       // promise.progress = list.add
+                       // promise.done = list.add
+                       // promise.fail = list.add
+                       promise[ tuple[ 1 ] ] = list.add;
+
+                       // Handle state
+                       if ( stateString ) {
+                               list.add(
+                                       function() {
+
+                                               // state = "resolved" (i.e., fulfilled)
+                                               // state = "rejected"
+                                               state = stateString;
+                                       },
+
+                                       // rejected_callbacks.disable
+                                       // fulfilled_callbacks.disable
+                                       tuples[ 3 - i ][ 2 ].disable,
+
+                                       // rejected_handlers.disable
+                                       // fulfilled_handlers.disable
+                                       tuples[ 3 - i ][ 3 ].disable,
+
+                                       // progress_callbacks.lock
+                                       tuples[ 0 ][ 2 ].lock,
+
+                                       // progress_handlers.lock
+                                       tuples[ 0 ][ 3 ].lock
+                               );
+                       }
+
+                       // progress_handlers.fire
+                       // fulfilled_handlers.fire
+                       // rejected_handlers.fire
+                       list.add( tuple[ 3 ].fire );
+
+                       // deferred.notify = function() { deferred.notifyWith(...) }
+                       // deferred.resolve = function() { deferred.resolveWith(...) }
+                       // deferred.reject = function() { deferred.rejectWith(...) }
+                       deferred[ tuple[ 0 ] ] = function() {
+                               deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
+                               return this;
+                       };
+
+                       // deferred.notifyWith = list.fireWith
+                       // deferred.resolveWith = list.fireWith
+                       // deferred.rejectWith = list.fireWith
+                       deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+               } );
+
+               // Make the deferred a promise
+               promise.promise( deferred );
+
+               // Call given func if any
+               if ( func ) {
+                       func.call( deferred, deferred );
+               }
+
+               // All done!
+               return deferred;
+       },
+
+       // Deferred helper
+       when: function( singleValue ) {
+               var
+
+                       // count of uncompleted subordinates
+                       remaining = arguments.length,
+
+                       // count of unprocessed arguments
+                       i = remaining,
+
+                       // subordinate fulfillment data
+                       resolveContexts = Array( i ),
+                       resolveValues = slice.call( arguments ),
+
+                       // the master Deferred
+                       master = jQuery.Deferred(),
+
+                       // subordinate callback factory
+                       updateFunc = function( i ) {
+                               return function( value ) {
+                                       resolveContexts[ i ] = this;
+                                       resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+                                       if ( !( --remaining ) ) {
+                                               master.resolveWith( resolveContexts, resolveValues );
+                                       }
+                               };
+                       };
+
+               // Single- and empty arguments are adopted like Promise.resolve
+               if ( remaining <= 1 ) {
+                       adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
+                               !remaining );
+
+                       // Use .then() to unwrap secondary thenables (cf. gh-3000)
+                       if ( master.state() === "pending" ||
+                               isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+
+                               return master.then();
+                       }
+               }
+
+               // Multiple arguments are aggregated like Promise.all array elements
+               while ( i-- ) {
+                       adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
+               }
+
+               return master.promise();
+       }
+} );
+
+
+// These usually indicate a programmer mistake during development,
+// warn about them ASAP rather than swallowing them by default.
+var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+
+jQuery.Deferred.exceptionHook = function( error, stack ) {
+
+       // Support: IE 8 - 9 only
+       // Console exists when dev tools are open, which can happen at any time
+       if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
+               window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+       }
+};
+
+
+
+
+jQuery.readyException = function( error ) {
+       window.setTimeout( function() {
+               throw error;
+       } );
+};
+
+
+
+
+// The deferred used on DOM ready
+var readyList = jQuery.Deferred();
+
+jQuery.fn.ready = function( fn ) {
+
+       readyList
+               .then( fn )
+
+               // Wrap jQuery.readyException in a function so that the lookup
+               // happens at the time of error handling instead of callback
+               // registration.
+               .catch( function( error ) {
+                       jQuery.readyException( error );
+               } );
+
+       return this;
+};
+
+jQuery.extend( {
+
+       // Is the DOM ready to be used? Set to true once it occurs.
+       isReady: false,
+
+       // A counter to track how many items to wait for before
+       // the ready event fires. See #6781
+       readyWait: 1,
+
+       // Handle when the DOM is ready
+       ready: function( wait ) {
+
+               // Abort if there are pending holds or we're already ready
+               if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+                       return;
+               }
+
+               // Remember that the DOM is ready
+               jQuery.isReady = true;
+
+               // If a normal DOM Ready event fired, decrement, and wait if need be
+               if ( wait !== true && --jQuery.readyWait > 0 ) {
+                       return;
+               }
+
+               // If there are functions bound, to execute
+               readyList.resolveWith( document, [ jQuery ] );
+       }
+} );
+
+jQuery.ready.then = readyList.then;
+
+// The ready event handler and self cleanup method
+function completed() {
+       document.removeEventListener( "DOMContentLoaded", completed );
+       window.removeEventListener( "load", completed );
+       jQuery.ready();
+}
+
+// Catch cases where $(document).ready() is called
+// after the browser event has already occurred.
+// Support: IE <=9 - 10 only
+// Older IE sometimes signals "interactive" too soon
+if ( document.readyState === "complete" ||
+       ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+       // Handle it asynchronously to allow scripts the opportunity to delay ready
+       window.setTimeout( jQuery.ready );
+
+} else {
+
+       // Use the handy event callback
+       document.addEventListener( "DOMContentLoaded", completed );
+
+       // A fallback to window.onload, that will always work
+       window.addEventListener( "load", completed );
+}
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+       var i = 0,
+               len = elems.length,
+               bulk = key == null;
+
+       // Sets many values
+       if ( toType( key ) === "object" ) {
+               chainable = true;
+               for ( i in key ) {
+                       access( elems, fn, i, key[ i ], true, emptyGet, raw );
+               }
+
+       // Sets one value
+       } else if ( value !== undefined ) {
+               chainable = true;
+
+               if ( !isFunction( value ) ) {
+                       raw = true;
+               }
+
+               if ( bulk ) {
+
+                       // Bulk operations run against the entire set
+                       if ( raw ) {
+                               fn.call( elems, value );
+                               fn = null;
+
+                       // ...except when executing function values
+                       } else {
+                               bulk = fn;
+                               fn = function( elem, _key, value ) {
+                                       return bulk.call( jQuery( elem ), value );
+                               };
+                       }
+               }
+
+               if ( fn ) {
+                       for ( ; i < len; i++ ) {
+                               fn(
+                                       elems[ i ], key, raw ?
+                                       value :
+                                       value.call( elems[ i ], i, fn( elems[ i ], key ) )
+                               );
+                       }
+               }
+       }
+
+       if ( chainable ) {
+               return elems;
+       }
+
+       // Gets
+       if ( bulk ) {
+               return fn.call( elems );
+       }
+
+       return len ? fn( elems[ 0 ], key ) : emptyGet;
+};
+
+
+// Matches dashed string for camelizing
+var rmsPrefix = /^-ms-/,
+       rdashAlpha = /-([a-z])/g;
+
+// Used by camelCase as callback to replace()
+function fcamelCase( _all, letter ) {
+       return letter.toUpperCase();
+}
+
+// Convert dashed to camelCase; used by the css and data modules
+// Support: IE <=9 - 11, Edge 12 - 15
+// Microsoft forgot to hump their vendor prefix (#9572)
+function camelCase( string ) {
+       return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+}
+var acceptData = function( owner ) {
+
+       // Accepts only:
+       //  - Node
+       //    - Node.ELEMENT_NODE
+       //    - Node.DOCUMENT_NODE
+       //  - Object
+       //    - Any
+       return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+
+
+function Data() {
+       this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+
+Data.prototype = {
+
+       cache: function( owner ) {
+
+               // Check if the owner object already has a cache
+               var value = owner[ this.expando ];
+
+               // If not, create one
+               if ( !value ) {
+                       value = {};
+
+                       // We can accept data for non-element nodes in modern browsers,
+                       // but we should not, see #8335.
+                       // Always return an empty object.
+                       if ( acceptData( owner ) ) {
+
+                               // If it is a node unlikely to be stringify-ed or looped over
+                               // use plain assignment
+                               if ( owner.nodeType ) {
+                                       owner[ this.expando ] = value;
+
+                               // Otherwise secure it in a non-enumerable property
+                               // configurable must be true to allow the property to be
+                               // deleted when data is removed
+                               } else {
+                                       Object.defineProperty( owner, this.expando, {
+                                               value: value,
+                                               configurable: true
+                                       } );
+                               }
+                       }
+               }
+
+               return value;
+       },
+       set: function( owner, data, value ) {
+               var prop,
+                       cache = this.cache( owner );
+
+               // Handle: [ owner, key, value ] args
+               // Always use camelCase key (gh-2257)
+               if ( typeof data === "string" ) {
+                       cache[ camelCase( data ) ] = value;
+
+               // Handle: [ owner, { properties } ] args
+               } else {
+
+                       // Copy the properties one-by-one to the cache object
+                       for ( prop in data ) {
+                               cache[ camelCase( prop ) ] = data[ prop ];
+                       }
+               }
+               return cache;
+       },
+       get: function( owner, key ) {
+               return key === undefined ?
+                       this.cache( owner ) :
+
+                       // Always use camelCase key (gh-2257)
+                       owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
+       },
+       access: function( owner, key, value ) {
+
+               // In cases where either:
+               //
+               //   1. No key was specified
+               //   2. A string key was specified, but no value provided
+               //
+               // Take the "read" path and allow the get method to determine
+               // which value to return, respectively either:
+               //
+               //   1. The entire cache object
+               //   2. The data stored at the key
+               //
+               if ( key === undefined ||
+                               ( ( key && typeof key === "string" ) && value === undefined ) ) {
+
+                       return this.get( owner, key );
+               }
+
+               // When the key is not a string, or both a key and value
+               // are specified, set or extend (existing objects) with either:
+               //
+               //   1. An object of properties
+               //   2. A key and value
+               //
+               this.set( owner, key, value );
+
+               // Since the "set" path can have two possible entry points
+               // return the expected data based on which path was taken[*]
+               return value !== undefined ? value : key;
+       },
+       remove: function( owner, key ) {
+               var i,
+                       cache = owner[ this.expando ];
+
+               if ( cache === undefined ) {
+                       return;
+               }
+
+               if ( key !== undefined ) {
+
+                       // Support array or space separated string of keys
+                       if ( Array.isArray( key ) ) {
+
+                               // If key is an array of keys...
+                               // We always set camelCase keys, so remove that.
+                               key = key.map( camelCase );
+                       } else {
+                               key = camelCase( key );
+
+                               // If a key with the spaces exists, use it.
+                               // Otherwise, create an array by matching non-whitespace
+                               key = key in cache ?
+                                       [ key ] :
+                                       ( key.match( rnothtmlwhite ) || [] );
+                       }
+
+                       i = key.length;
+
+                       while ( i-- ) {
+                               delete cache[ key[ i ] ];
+                       }
+               }
+
+               // Remove the expando if there's no more data
+               if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
+
+                       // Support: Chrome <=35 - 45
+                       // Webkit & Blink performance suffers when deleting properties
+                       // from DOM nodes, so set to undefined instead
+                       // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
+                       if ( owner.nodeType ) {
+                               owner[ this.expando ] = undefined;
+                       } else {
+                               delete owner[ this.expando ];
+                       }
+               }
+       },
+       hasData: function( owner ) {
+               var cache = owner[ this.expando ];
+               return cache !== undefined && !jQuery.isEmptyObject( cache );
+       }
+};
+var dataPriv = new Data();
+
+var dataUser = new Data();
+
+
+
+//     Implementation Summary
+//
+//     1. Enforce API surface and semantic compatibility with 1.9.x branch
+//     2. Improve the module's maintainability by reducing the storage
+//             paths to a single mechanism.
+//     3. Use the same single mechanism to support "private" and "user" data.
+//     4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+//     5. Avoid exposing implementation details on user objects (eg. expando properties)
+//     6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+       rmultiDash = /[A-Z]/g;
+
+function getData( data ) {
+       if ( data === "true" ) {
+               return true;
+       }
+
+       if ( data === "false" ) {
+               return false;
+       }
+
+       if ( data === "null" ) {
+               return null;
+       }
+
+       // Only convert to a number if it doesn't change the string
+       if ( data === +data + "" ) {
+               return +data;
+       }
+
+       if ( rbrace.test( data ) ) {
+               return JSON.parse( data );
+       }
+
+       return data;
+}
+
+function dataAttr( elem, key, data ) {
+       var name;
+
+       // If nothing was found internally, try to fetch any
+       // data from the HTML5 data-* attribute
+       if ( data === undefined && elem.nodeType === 1 ) {
+               name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
+               data = elem.getAttribute( name );
+
+               if ( typeof data === "string" ) {
+                       try {
+                               data = getData( data );
+                       } catch ( e ) {}
+
+                       // Make sure we set the data so it isn't changed later
+                       dataUser.set( elem, key, data );
+               } else {
+                       data = undefined;
+               }
+       }
+       return data;
+}
+
+jQuery.extend( {
+       hasData: function( elem ) {
+               return dataUser.hasData( elem ) || dataPriv.hasData( elem );
+       },
+
+       data: function( elem, name, data ) {
+               return dataUser.access( elem, name, data );
+       },
+
+       removeData: function( elem, name ) {
+               dataUser.remove( elem, name );
+       },
+
+       // TODO: Now that all calls to _data and _removeData have been replaced
+       // with direct calls to dataPriv methods, these can be deprecated.
+       _data: function( elem, name, data ) {
+               return dataPriv.access( elem, name, data );
+       },
+
+       _removeData: function( elem, name ) {
+               dataPriv.remove( elem, name );
+       }
+} );
+
+jQuery.fn.extend( {
+       data: function( key, value ) {
+               var i, name, data,
+                       elem = this[ 0 ],
+                       attrs = elem && elem.attributes;
+
+               // Gets all values
+               if ( key === undefined ) {
+                       if ( this.length ) {
+                               data = dataUser.get( elem );
+
+                               if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
+                                       i = attrs.length;
+                                       while ( i-- ) {
+
+                                               // Support: IE 11 only
+                                               // The attrs elements can be null (#14894)
+                                               if ( attrs[ i ] ) {
+                                                       name = attrs[ i ].name;
+                                                       if ( name.indexOf( "data-" ) === 0 ) {
+                                                               name = camelCase( name.slice( 5 ) );
+                                                               dataAttr( elem, name, data[ name ] );
+                                                       }
+                                               }
+                                       }
+                                       dataPriv.set( elem, "hasDataAttrs", true );
+                               }
+                       }
+
+                       return data;
+               }
+
+               // Sets multiple values
+               if ( typeof key === "object" ) {
+                       return this.each( function() {
+                               dataUser.set( this, key );
+                       } );
+               }
+
+               return access( this, function( value ) {
+                       var data;
+
+                       // The calling jQuery object (element matches) is not empty
+                       // (and therefore has an element appears at this[ 0 ]) and the
+                       // `value` parameter was not undefined. An empty jQuery object
+                       // will result in `undefined` for elem = this[ 0 ] which will
+                       // throw an exception if an attempt to read a data cache is made.
+                       if ( elem && value === undefined ) {
+
+                               // Attempt to get data from the cache
+                               // The key will always be camelCased in Data
+                               data = dataUser.get( elem, key );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // Attempt to "discover" the data in
+                               // HTML5 custom data-* attrs
+                               data = dataAttr( elem, key );
+                               if ( data !== undefined ) {
+                                       return data;
+                               }
+
+                               // We tried really hard, but the data doesn't exist.
+                               return;
+                       }
+
+                       // Set the data...
+                       this.each( function() {
+
+                               // We always store the camelCased key
+                               dataUser.set( this, key, value );
+                       } );
+               }, null, value, arguments.length > 1, null, true );
+       },
+
+       removeData: function( key ) {
+               return this.each( function() {
+                       dataUser.remove( this, key );
+               } );
+       }
+} );
+
+
+jQuery.extend( {
+       queue: function( elem, type, data ) {
+               var queue;
+
+               if ( elem ) {
+                       type = ( type || "fx" ) + "queue";
+                       queue = dataPriv.get( elem, type );
+
+                       // Speed up dequeue by getting out quickly if this is just a lookup
+                       if ( data ) {
+                               if ( !queue || Array.isArray( data ) ) {
+                                       queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
+                               } else {
+                                       queue.push( data );
+                               }
+                       }
+                       return queue || [];
+               }
+       },
+
+       dequeue: function( elem, type ) {
+               type = type || "fx";
+
+               var queue = jQuery.queue( elem, type ),
+                       startLength = queue.length,
+                       fn = queue.shift(),
+                       hooks = jQuery._queueHooks( elem, type ),
+                       next = function() {
+                               jQuery.dequeue( elem, type );
+                       };
+
+               // If the fx queue is dequeued, always remove the progress sentinel
+               if ( fn === "inprogress" ) {
+                       fn = queue.shift();
+                       startLength--;
+               }
+
+               if ( fn ) {
+
+                       // Add a progress sentinel to prevent the fx queue from being
+                       // automatically dequeued
+                       if ( type === "fx" ) {
+                               queue.unshift( "inprogress" );
+                       }
+
+                       // Clear up the last queue stop function
+                       delete hooks.stop;
+                       fn.call( elem, next, hooks );
+               }
+
+               if ( !startLength && hooks ) {
+                       hooks.empty.fire();
+               }
+       },
+
+       // Not public - generate a queueHooks object, or return the current one
+       _queueHooks: function( elem, type ) {
+               var key = type + "queueHooks";
+               return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+                       empty: jQuery.Callbacks( "once memory" ).add( function() {
+                               dataPriv.remove( elem, [ type + "queue", key ] );
+                       } )
+               } );
+       }
+} );
+
+jQuery.fn.extend( {
+       queue: function( type, data ) {
+               var setter = 2;
+
+               if ( typeof type !== "string" ) {
+                       data = type;
+                       type = "fx";
+                       setter--;
+               }
+
+               if ( arguments.length < setter ) {
+                       return jQuery.queue( this[ 0 ], type );
+               }
+
+               return data === undefined ?
+                       this :
+                       this.each( function() {
+                               var queue = jQuery.queue( this, type, data );
+
+                               // Ensure a hooks for this queue
+                               jQuery._queueHooks( this, type );
+
+                               if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
+                                       jQuery.dequeue( this, type );
+                               }
+                       } );
+       },
+       dequeue: function( type ) {
+               return this.each( function() {
+                       jQuery.dequeue( this, type );
+               } );
+       },
+       clearQueue: function( type ) {
+               return this.queue( type || "fx", [] );
+       },
+
+       // Get a promise resolved when queues of a certain type
+       // are emptied (fx is the type by default)
+       promise: function( type, obj ) {
+               var tmp,
+                       count = 1,
+                       defer = jQuery.Deferred(),
+                       elements = this,
+                       i = this.length,
+                       resolve = function() {
+                               if ( !( --count ) ) {
+                                       defer.resolveWith( elements, [ elements ] );
+                               }
+                       };
+
+               if ( typeof type !== "string" ) {
+                       obj = type;
+                       type = undefined;
+               }
+               type = type || "fx";
+
+               while ( i-- ) {
+                       tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
+                       if ( tmp && tmp.empty ) {
+                               count++;
+                               tmp.empty.add( resolve );
+                       }
+               }
+               resolve();
+               return defer.promise( obj );
+       }
+} );
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var documentElement = document.documentElement;
+
+
+
+       var isAttached = function( elem ) {
+                       return jQuery.contains( elem.ownerDocument, elem );
+               },
+               composed = { composed: true };
+
+       // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
+       // Check attachment across shadow DOM boundaries when possible (gh-3504)
+       // Support: iOS 10.0-10.2 only
+       // Early iOS 10 versions support `attachShadow` but not `getRootNode`,
+       // leading to errors. We need to check for `getRootNode`.
+       if ( documentElement.getRootNode ) {
+               isAttached = function( elem ) {
+                       return jQuery.contains( elem.ownerDocument, elem ) ||
+                               elem.getRootNode( composed ) === elem.ownerDocument;
+               };
+       }
+var isHiddenWithinTree = function( elem, el ) {
+
+               // isHiddenWithinTree might be called from jQuery#filter function;
+               // in that case, element will be second argument
+               elem = el || elem;
+
+               // Inline style trumps all
+               return elem.style.display === "none" ||
+                       elem.style.display === "" &&
+
+                       // Otherwise, check computed style
+                       // Support: Firefox <=43 - 45
+                       // Disconnected elements can have computed display: none, so first confirm that elem is
+                       // in the document.
+                       isAttached( elem ) &&
+
+                       jQuery.css( elem, "display" ) === "none";
+       };
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+       var adjusted, scale,
+               maxIterations = 20,
+               currentValue = tween ?
+                       function() {
+                               return tween.cur();
+                       } :
+                       function() {
+                               return jQuery.css( elem, prop, "" );
+                       },
+               initial = currentValue(),
+               unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+               // Starting value computation is required for potential unit mismatches
+               initialInUnit = elem.nodeType &&
+                       ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+                       rcssNum.exec( jQuery.css( elem, prop ) );
+
+       if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+               // Support: Firefox <=54
+               // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
+               initial = initial / 2;
+
+               // Trust units reported by jQuery.css
+               unit = unit || initialInUnit[ 3 ];
+
+               // Iteratively approximate from a nonzero starting point
+               initialInUnit = +initial || 1;
+
+               while ( maxIterations-- ) {
+
+                       // Evaluate and update our best guess (doubling guesses that zero out).
+                       // Finish if the scale equals or crosses 1 (making the old*new product non-positive).
+                       jQuery.style( elem, prop, initialInUnit + unit );
+                       if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
+                               maxIterations = 0;
+                       }
+                       initialInUnit = initialInUnit / scale;
+
+               }
+
+               initialInUnit = initialInUnit * 2;
+               jQuery.style( elem, prop, initialInUnit + unit );
+
+               // Make sure we update the tween properties later on
+               valueParts = valueParts || [];
+       }
+
+       if ( valueParts ) {
+               initialInUnit = +initialInUnit || +initial || 0;
+
+               // Apply relative offset (+=/-=) if specified
+               adjusted = valueParts[ 1 ] ?
+                       initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+                       +valueParts[ 2 ];
+               if ( tween ) {
+                       tween.unit = unit;
+                       tween.start = initialInUnit;
+                       tween.end = adjusted;
+               }
+       }
+       return adjusted;
+}
+
+
+var defaultDisplayMap = {};
+
+function getDefaultDisplay( elem ) {
+       var temp,
+               doc = elem.ownerDocument,
+               nodeName = elem.nodeName,
+               display = defaultDisplayMap[ nodeName ];
+
+       if ( display ) {
+               return display;
+       }
+
+       temp = doc.body.appendChild( doc.createElement( nodeName ) );
+       display = jQuery.css( temp, "display" );
+
+       temp.parentNode.removeChild( temp );
+
+       if ( display === "none" ) {
+               display = "block";
+       }
+       defaultDisplayMap[ nodeName ] = display;
+
+       return display;
+}
+
+function showHide( elements, show ) {
+       var display, elem,
+               values = [],
+               index = 0,
+               length = elements.length;
+
+       // Determine new display value for elements that need to change
+       for ( ; index < length; index++ ) {
+               elem = elements[ index ];
+               if ( !elem.style ) {
+                       continue;
+               }
+
+               display = elem.style.display;
+               if ( show ) {
+
+                       // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
+                       // check is required in this first loop unless we have a nonempty display value (either
+                       // inline or about-to-be-restored)
+                       if ( display === "none" ) {
+                               values[ index ] = dataPriv.get( elem, "display" ) || null;
+                               if ( !values[ index ] ) {
+                                       elem.style.display = "";
+                               }
+                       }
+                       if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
+                               values[ index ] = getDefaultDisplay( elem );
+                       }
+               } else {
+                       if ( display !== "none" ) {
+                               values[ index ] = "none";
+
+                               // Remember what we're overwriting
+                               dataPriv.set( elem, "display", display );
+                       }
+               }
+       }
+
+       // Set the display of the elements in a second loop to avoid constant reflow
+       for ( index = 0; index < length; index++ ) {
+               if ( values[ index ] != null ) {
+                       elements[ index ].style.display = values[ index ];
+               }
+       }
+
+       return elements;
+}
+
+jQuery.fn.extend( {
+       show: function() {
+               return showHide( this, true );
+       },
+       hide: function() {
+               return showHide( this );
+       },
+       toggle: function( state ) {
+               if ( typeof state === "boolean" ) {
+                       return state ? this.show() : this.hide();
+               }
+
+               return this.each( function() {
+                       if ( isHiddenWithinTree( this ) ) {
+                               jQuery( this ).show();
+                       } else {
+                               jQuery( this ).hide();
+                       }
+               } );
+       }
+} );
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
+
+var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
+
+
+
+( function() {
+       var fragment = document.createDocumentFragment(),
+               div = fragment.appendChild( document.createElement( "div" ) ),
+               input = document.createElement( "input" );
+
+       // Support: Android 4.0 - 4.3 only
+       // Check state lost if the name is set (#11217)
+       // Support: Windows Web Apps (WWA)
+       // `name` and `type` must use .setAttribute for WWA (#14901)
+       input.setAttribute( "type", "radio" );
+       input.setAttribute( "checked", "checked" );
+       input.setAttribute( "name", "t" );
+
+       div.appendChild( input );
+
+       // Support: Android <=4.1 only
+       // Older WebKit doesn't clone checked state correctly in fragments
+       support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+       // Support: IE <=11 only
+       // Make sure textarea (and checkbox) defaultValue is properly cloned
+       div.innerHTML = "<textarea>x</textarea>";
+       support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+       // Support: IE <=9 only
+       // IE <=9 replaces <option> tags with their contents when inserted outside of
+       // the select element.
+       div.innerHTML = "<option></option>";
+       support.option = !!div.lastChild;
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
+
+       // XHTML parsers do not magically insert elements in the
+       // same way that tag soup parsers do. So we cannot shorten
+       // this by omitting <tbody> or other required elements.
+       thead: [ 1, "<table>", "</table>" ],
+       col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+       tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+       td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+       _default: [ 0, "", "" ]
+};
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: IE <=9 only
+if ( !support.option ) {
+       wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
+}
+
+
+function getAll( context, tag ) {
+
+       // Support: IE <=9 - 11 only
+       // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+       var ret;
+
+       if ( typeof context.getElementsByTagName !== "undefined" ) {
+               ret = context.getElementsByTagName( tag || "*" );
+
+       } else if ( typeof context.querySelectorAll !== "undefined" ) {
+               ret = context.querySelectorAll( tag || "*" );
+
+       } else {
+               ret = [];
+       }
+
+       if ( tag === undefined || tag && nodeName( context, tag ) ) {
+               return jQuery.merge( [ context ], ret );
+       }
+
+       return ret;
+}
+
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+       var i = 0,
+               l = elems.length;
+
+       for ( ; i < l; i++ ) {
+               dataPriv.set(
+                       elems[ i ],
+                       "globalEval",
+                       !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+               );
+       }
+}
+
+
+var rhtml = /<|&#?\w+;/;
+
+function buildFragment( elems, context, scripts, selection, ignored ) {
+       var elem, tmp, tag, wrap, attached, j,
+               fragment = context.createDocumentFragment(),
+               nodes = [],
+               i = 0,
+               l = elems.length;
+
+       for ( ; i < l; i++ ) {
+               elem = elems[ i ];
+
+               if ( elem || elem === 0 ) {
+
+                       // Add nodes directly
+                       if ( toType( elem ) === "object" ) {
+
+                               // Support: Android <=4.0 only, PhantomJS 1 only
+                               // push.apply(_, arraylike) throws on ancient WebKit
+                               jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+                       // Convert non-html into a text node
+                       } else if ( !rhtml.test( elem ) ) {
+                               nodes.push( context.createTextNode( elem ) );
+
+                       // Convert html into DOM nodes
+                       } else {
+                               tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
+
+                               // Deserialize a standard representation
+                               tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+                               wrap = wrapMap[ tag ] || wrapMap._default;
+                               tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+                               // Descend through wrappers to the right content
+                               j = wrap[ 0 ];
+                               while ( j-- ) {
+                                       tmp = tmp.lastChild;
+                               }
+
+                               // Support: Android <=4.0 only, PhantomJS 1 only
+                               // push.apply(_, arraylike) throws on ancient WebKit
+                               jQuery.merge( nodes, tmp.childNodes );
+
+                               // Remember the top-level container
+                               tmp = fragment.firstChild;
+
+                               // Ensure the created nodes are orphaned (#12392)
+                               tmp.textContent = "";
+                       }
+               }
+       }
+
+       // Remove wrapper from fragment
+       fragment.textContent = "";
+
+       i = 0;
+       while ( ( elem = nodes[ i++ ] ) ) {
+
+               // Skip elements already in the context collection (trac-4087)
+               if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+                       if ( ignored ) {
+                               ignored.push( elem );
+                       }
+                       continue;
+               }
+
+               attached = isAttached( elem );
+
+               // Append to fragment
+               tmp = getAll( fragment.appendChild( elem ), "script" );
+
+               // Preserve script evaluation history
+               if ( attached ) {
+                       setGlobalEval( tmp );
+               }
+
+               // Capture executables
+               if ( scripts ) {
+                       j = 0;
+                       while ( ( elem = tmp[ j++ ] ) ) {
+                               if ( rscriptType.test( elem.type || "" ) ) {
+                                       scripts.push( elem );
+                               }
+                       }
+               }
+       }
+
+       return fragment;
+}
+
+
+var
+       rkeyEvent = /^key/,
+       rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+       rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+function returnTrue() {
+       return true;
+}
+
+function returnFalse() {
+       return false;
+}
+
+// Support: IE <=9 - 11+
+// focus() and blur() are asynchronous, except when they are no-op.
+// So expect focus to be synchronous when the element is already active,
+// and blur to be synchronous when the element is not already active.
+// (focus and blur are always synchronous in other supported browsers,
+// this just defines when we can count on it).
+function expectSync( elem, type ) {
+       return ( elem === safeActiveElement() ) === ( type === "focus" );
+}
+
+// Support: IE <=9 only
+// Accessing document.activeElement can throw unexpectedly
+// https://bugs.jquery.com/ticket/13393
+function safeActiveElement() {
+       try {
+               return document.activeElement;
+       } catch ( err ) { }
+}
+
+function on( elem, types, selector, data, fn, one ) {
+       var origFn, type;
+
+       // Types can be a map of types/handlers
+       if ( typeof types === "object" ) {
+
+               // ( types-Object, selector, data )
+               if ( typeof selector !== "string" ) {
+
+                       // ( types-Object, data )
+                       data = data || selector;
+                       selector = undefined;
+               }
+               for ( type in types ) {
+                       on( elem, type, selector, data, types[ type ], one );
+               }
+               return elem;
+       }
+
+       if ( data == null && fn == null ) {
+
+               // ( types, fn )
+               fn = selector;
+               data = selector = undefined;
+       } else if ( fn == null ) {
+               if ( typeof selector === "string" ) {
+
+                       // ( types, selector, fn )
+                       fn = data;
+                       data = undefined;
+               } else {
+
+                       // ( types, data, fn )
+                       fn = data;
+                       data = selector;
+                       selector = undefined;
+               }
+       }
+       if ( fn === false ) {
+               fn = returnFalse;
+       } else if ( !fn ) {
+               return elem;
+       }
+
+       if ( one === 1 ) {
+               origFn = fn;
+               fn = function( event ) {
+
+                       // Can use an empty set, since event contains the info
+                       jQuery().off( event );
+                       return origFn.apply( this, arguments );
+               };
+
+               // Use same guid so caller can remove using origFn
+               fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+       }
+       return elem.each( function() {
+               jQuery.event.add( this, types, fn, data, selector );
+       } );
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+       global: {},
+
+       add: function( elem, types, handler, data, selector ) {
+
+               var handleObjIn, eventHandle, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = dataPriv.get( elem );
+
+               // Only attach events to objects that accept data
+               if ( !acceptData( elem ) ) {
+                       return;
+               }
+
+               // Caller can pass in an object of custom data in lieu of the handler
+               if ( handler.handler ) {
+                       handleObjIn = handler;
+                       handler = handleObjIn.handler;
+                       selector = handleObjIn.selector;
+               }
+
+               // Ensure that invalid selectors throw exceptions at attach time
+               // Evaluate against documentElement in case elem is a non-element node (e.g., document)
+               if ( selector ) {
+                       jQuery.find.matchesSelector( documentElement, selector );
+               }
+
+               // Make sure that the handler has a unique ID, used to find/remove it later
+               if ( !handler.guid ) {
+                       handler.guid = jQuery.guid++;
+               }
+
+               // Init the element's event structure and main handler, if this is the first
+               if ( !( events = elemData.events ) ) {
+                       events = elemData.events = Object.create( null );
+               }
+               if ( !( eventHandle = elemData.handle ) ) {
+                       eventHandle = elemData.handle = function( e ) {
+
+                               // Discard the second event of a jQuery.event.trigger() and
+                               // when an event is called after a page has unloaded
+                               return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
+                                       jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+                       };
+               }
+
+               // Handle multiple events separated by a space
+               types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[ t ] ) || [];
+                       type = origType = tmp[ 1 ];
+                       namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+                       // There *must* be a type, no attaching namespace-only handlers
+                       if ( !type ) {
+                               continue;
+                       }
+
+                       // If event changes its type, use the special event handlers for the changed type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // If selector defined, determine special event api type, otherwise given type
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+
+                       // Update special based on newly reset type
+                       special = jQuery.event.special[ type ] || {};
+
+                       // handleObj is passed to all event handlers
+                       handleObj = jQuery.extend( {
+                               type: type,
+                               origType: origType,
+                               data: data,
+                               handler: handler,
+                               guid: handler.guid,
+                               selector: selector,
+                               needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+                               namespace: namespaces.join( "." )
+                       }, handleObjIn );
+
+                       // Init the event handler queue if we're the first
+                       if ( !( handlers = events[ type ] ) ) {
+                               handlers = events[ type ] = [];
+                               handlers.delegateCount = 0;
+
+                               // Only use addEventListener if the special events handler returns false
+                               if ( !special.setup ||
+                                       special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+
+                                       if ( elem.addEventListener ) {
+                                               elem.addEventListener( type, eventHandle );
+                                       }
+                               }
+                       }
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
+
+                               if ( !handleObj.handler.guid ) {
+                                       handleObj.handler.guid = handler.guid;
+                               }
+                       }
+
+                       // Add to the element's handler list, delegates in front
+                       if ( selector ) {
+                               handlers.splice( handlers.delegateCount++, 0, handleObj );
+                       } else {
+                               handlers.push( handleObj );
+                       }
+
+                       // Keep track of which events have ever been used, for event optimization
+                       jQuery.event.global[ type ] = true;
+               }
+
+       },
+
+       // Detach an event or set of events from an element
+       remove: function( elem, types, handler, selector, mappedTypes ) {
+
+               var j, origCount, tmp,
+                       events, t, handleObj,
+                       special, handlers, type, namespaces, origType,
+                       elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+               if ( !elemData || !( events = elemData.events ) ) {
+                       return;
+               }
+
+               // Once for each type.namespace in types; type may be omitted
+               types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+               t = types.length;
+               while ( t-- ) {
+                       tmp = rtypenamespace.exec( types[ t ] ) || [];
+                       type = origType = tmp[ 1 ];
+                       namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+                       // Unbind all events (on this namespace, if provided) for the element
+                       if ( !type ) {
+                               for ( type in events ) {
+                                       jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+                               }
+                               continue;
+                       }
+
+                       special = jQuery.event.special[ type ] || {};
+                       type = ( selector ? special.delegateType : special.bindType ) || type;
+                       handlers = events[ type ] || [];
+                       tmp = tmp[ 2 ] &&
+                               new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
+
+                       // Remove matching events
+                       origCount = j = handlers.length;
+                       while ( j-- ) {
+                               handleObj = handlers[ j ];
+
+                               if ( ( mappedTypes || origType === handleObj.origType ) &&
+                                       ( !handler || handler.guid === handleObj.guid ) &&
+                                       ( !tmp || tmp.test( handleObj.namespace ) ) &&
+                                       ( !selector || selector === handleObj.selector ||
+                                               selector === "**" && handleObj.selector ) ) {
+                                       handlers.splice( j, 1 );
+
+                                       if ( handleObj.selector ) {
+                                               handlers.delegateCount--;
+                                       }
+                                       if ( special.remove ) {
+                                               special.remove.call( elem, handleObj );
+                                       }
+                               }
+                       }
+
+                       // Remove generic event handler if we removed something and no more handlers exist
+                       // (avoids potential for endless recursion during removal of special event handlers)
+                       if ( origCount && !handlers.length ) {
+                               if ( !special.teardown ||
+                                       special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
+                                       jQuery.removeEvent( elem, type, elemData.handle );
+                               }
+
+                               delete events[ type ];
+                       }
+               }
+
+               // Remove data and the expando if it's no longer used
+               if ( jQuery.isEmptyObject( events ) ) {
+                       dataPriv.remove( elem, "handle events" );
+               }
+       },
+
+       dispatch: function( nativeEvent ) {
+
+               var i, j, ret, matched, handleObj, handlerQueue,
+                       args = new Array( arguments.length ),
+
+                       // Make a writable jQuery.Event from the native event object
+                       event = jQuery.event.fix( nativeEvent ),
+
+                       handlers = (
+                                       dataPriv.get( this, "events" ) || Object.create( null )
+                               )[ event.type ] || [],
+                       special = jQuery.event.special[ event.type ] || {};
+
+               // Use the fix-ed jQuery.Event rather than the (read-only) native event
+               args[ 0 ] = event;
+
+               for ( i = 1; i < arguments.length; i++ ) {
+                       args[ i ] = arguments[ i ];
+               }
+
+               event.delegateTarget = this;
+
+               // Call the preDispatch hook for the mapped type, and let it bail if desired
+               if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+                       return;
+               }
+
+               // Determine handlers
+               handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+               // Run delegates first; they may want to stop propagation beneath us
+               i = 0;
+               while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
+                       event.currentTarget = matched.elem;
+
+                       j = 0;
+                       while ( ( handleObj = matched.handlers[ j++ ] ) &&
+                               !event.isImmediatePropagationStopped() ) {
+
+                               // If the event is namespaced, then each handler is only invoked if it is
+                               // specially universal or its namespaces are a superset of the event's.
+                               if ( !event.rnamespace || handleObj.namespace === false ||
+                                       event.rnamespace.test( handleObj.namespace ) ) {
+
+                                       event.handleObj = handleObj;
+                                       event.data = handleObj.data;
+
+                                       ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+                                               handleObj.handler ).apply( matched.elem, args );
+
+                                       if ( ret !== undefined ) {
+                                               if ( ( event.result = ret ) === false ) {
+                                                       event.preventDefault();
+                                                       event.stopPropagation();
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // Call the postDispatch hook for the mapped type
+               if ( special.postDispatch ) {
+                       special.postDispatch.call( this, event );
+               }
+
+               return event.result;
+       },
+
+       handlers: function( event, handlers ) {
+               var i, handleObj, sel, matchedHandlers, matchedSelectors,
+                       handlerQueue = [],
+                       delegateCount = handlers.delegateCount,
+                       cur = event.target;
+
+               // Find delegate handlers
+               if ( delegateCount &&
+
+                       // Support: IE <=9
+                       // Black-hole SVG <use> instance trees (trac-13180)
+                       cur.nodeType &&
+
+                       // Support: Firefox <=42
+                       // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
+                       // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
+                       // Support: IE 11 only
+                       // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
+                       !( event.type === "click" && event.button >= 1 ) ) {
+
+                       for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+                               // Don't check non-elements (#13208)
+                               // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+                               if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
+                                       matchedHandlers = [];
+                                       matchedSelectors = {};
+                                       for ( i = 0; i < delegateCount; i++ ) {
+                                               handleObj = handlers[ i ];
+
+                                               // Don't conflict with Object.prototype properties (#13203)
+                                               sel = handleObj.selector + " ";
+
+                                               if ( matchedSelectors[ sel ] === undefined ) {
+                                                       matchedSelectors[ sel ] = handleObj.needsContext ?
+                                                               jQuery( sel, this ).index( cur ) > -1 :
+                                                               jQuery.find( sel, this, null, [ cur ] ).length;
+                                               }
+                                               if ( matchedSelectors[ sel ] ) {
+                                                       matchedHandlers.push( handleObj );
+                                               }
+                                       }
+                                       if ( matchedHandlers.length ) {
+                                               handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
+                                       }
+                               }
+                       }
+               }
+
+               // Add the remaining (directly-bound) handlers
+               cur = this;
+               if ( delegateCount < handlers.length ) {
+                       handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
+               }
+
+               return handlerQueue;
+       },
+
+       addProp: function( name, hook ) {
+               Object.defineProperty( jQuery.Event.prototype, name, {
+                       enumerable: true,
+                       configurable: true,
+
+                       get: isFunction( hook ) ?
+                               function() {
+                                       if ( this.originalEvent ) {
+                                                       return hook( this.originalEvent );
+                                       }
+                               } :
+                               function() {
+                                       if ( this.originalEvent ) {
+                                                       return this.originalEvent[ name ];
+                                       }
+                               },
+
+                       set: function( value ) {
+                               Object.defineProperty( this, name, {
+                                       enumerable: true,
+                                       configurable: true,
+                                       writable: true,
+                                       value: value
+                               } );
+                       }
+               } );
+       },
+
+       fix: function( originalEvent ) {
+               return originalEvent[ jQuery.expando ] ?
+                       originalEvent :
+                       new jQuery.Event( originalEvent );
+       },
+
+       special: {
+               load: {
+
+                       // Prevent triggered image.load events from bubbling to window.load
+                       noBubble: true
+               },
+               click: {
+
+                       // Utilize native event to ensure correct state for checkable inputs
+                       setup: function( data ) {
+
+                               // For mutual compressibility with _default, replace `this` access with a local var.
+                               // `|| data` is dead code meant only to preserve the variable through minification.
+                               var el = this || data;
+
+                               // Claim the first handler
+                               if ( rcheckableType.test( el.type ) &&
+                                       el.click && nodeName( el, "input" ) ) {
+
+                                       // dataPriv.set( el, "click", ... )
+                                       leverageNative( el, "click", returnTrue );
+                               }
+
+                               // Return false to allow normal processing in the caller
+                               return false;
+                       },
+                       trigger: function( data ) {
+
+                               // For mutual compressibility with _default, replace `this` access with a local var.
+                               // `|| data` is dead code meant only to preserve the variable through minification.
+                               var el = this || data;
+
+                               // Force setup before triggering a click
+                               if ( rcheckableType.test( el.type ) &&
+                                       el.click && nodeName( el, "input" ) ) {
+
+                                       leverageNative( el, "click" );
+                               }
+
+                               // Return non-false to allow normal event-path propagation
+                               return true;
+                       },
+
+                       // For cross-browser consistency, suppress native .click() on links
+                       // Also prevent it if we're currently inside a leveraged native-event stack
+                       _default: function( event ) {
+                               var target = event.target;
+                               return rcheckableType.test( target.type ) &&
+                                       target.click && nodeName( target, "input" ) &&
+                                       dataPriv.get( target, "click" ) ||
+                                       nodeName( target, "a" );
+                       }
+               },
+
+               beforeunload: {
+                       postDispatch: function( event ) {
+
+                               // Support: Firefox 20+
+                               // Firefox doesn't alert if the returnValue field is not set.
+                               if ( event.result !== undefined && event.originalEvent ) {
+                                       event.originalEvent.returnValue = event.result;
+                               }
+                       }
+               }
+       }
+};
+
+// Ensure the presence of an event listener that handles manually-triggered
+// synthetic events by interrupting progress until reinvoked in response to
+// *native* events that it fires directly, ensuring that state changes have
+// already occurred before other listeners are invoked.
+function leverageNative( el, type, expectSync ) {
+
+       // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
+       if ( !expectSync ) {
+               if ( dataPriv.get( el, type ) === undefined ) {
+                       jQuery.event.add( el, type, returnTrue );
+               }
+               return;
+       }
+
+       // Register the controller as a special universal handler for all event namespaces
+       dataPriv.set( el, type, false );
+       jQuery.event.add( el, type, {
+               namespace: false,
+               handler: function( event ) {
+                       var notAsync, result,
+                               saved = dataPriv.get( this, type );
+
+                       if ( ( event.isTrigger & 1 ) && this[ type ] ) {
+
+                               // Interrupt processing of the outer synthetic .trigger()ed event
+                               // Saved data should be false in such cases, but might be a leftover capture object
+                               // from an async native handler (gh-4350)
+                               if ( !saved.length ) {
+
+                                       // Store arguments for use when handling the inner native event
+                                       // There will always be at least one argument (an event object), so this array
+                                       // will not be confused with a leftover capture object.
+                                       saved = slice.call( arguments );
+                                       dataPriv.set( this, type, saved );
+
+                                       // Trigger the native event and capture its result
+                                       // Support: IE <=9 - 11+
+                                       // focus() and blur() are asynchronous
+                                       notAsync = expectSync( this, type );
+                                       this[ type ]();
+                                       result = dataPriv.get( this, type );
+                                       if ( saved !== result || notAsync ) {
+                                               dataPriv.set( this, type, false );
+                                       } else {
+                                               result = {};
+                                       }
+                                       if ( saved !== result ) {
+
+                                               // Cancel the outer synthetic event
+                                               event.stopImmediatePropagation();
+                                               event.preventDefault();
+                                               return result.value;
+                                       }
+
+                               // If this is an inner synthetic event for an event with a bubbling surrogate
+                               // (focus or blur), assume that the surrogate already propagated from triggering the
+                               // native event and prevent that from happening again here.
+                               // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
+                               // bubbling surrogate propagates *after* the non-bubbling base), but that seems
+                               // less bad than duplication.
+                               } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
+                                       event.stopPropagation();
+                               }
+
+                       // If this is a native event triggered above, everything is now in order
+                       // Fire an inner synthetic event with the original arguments
+                       } else if ( saved.length ) {
+
+                               // ...and capture the result
+                               dataPriv.set( this, type, {
+                                       value: jQuery.event.trigger(
+
+                                               // Support: IE <=9 - 11+
+                                               // Extend with the prototype to reset the above stopImmediatePropagation()
+                                               jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
+                                               saved.slice( 1 ),
+                                               this
+                                       )
+                               } );
+
+                               // Abort handling of the native event
+                               event.stopImmediatePropagation();
+                       }
+               }
+       } );
+}
+
+jQuery.removeEvent = function( elem, type, handle ) {
+
+       // This "if" is needed for plain objects
+       if ( elem.removeEventListener ) {
+               elem.removeEventListener( type, handle );
+       }
+};
+
+jQuery.Event = function( src, props ) {
+
+       // Allow instantiation without the 'new' keyword
+       if ( !( this instanceof jQuery.Event ) ) {
+               return new jQuery.Event( src, props );
+       }
+
+       // Event object
+       if ( src && src.type ) {
+               this.originalEvent = src;
+               this.type = src.type;
+
+               // Events bubbling up the document may have been marked as prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = src.defaultPrevented ||
+                               src.defaultPrevented === undefined &&
+
+                               // Support: Android <=2.3 only
+                               src.returnValue === false ?
+                       returnTrue :
+                       returnFalse;
+
+               // Create target properties
+               // Support: Safari <=6 - 7 only
+               // Target should not be a text node (#504, #13143)
+               this.target = ( src.target && src.target.nodeType === 3 ) ?
+                       src.target.parentNode :
+                       src.target;
+
+               this.currentTarget = src.currentTarget;
+               this.relatedTarget = src.relatedTarget;
+
+       // Event type
+       } else {
+               this.type = src;
+       }
+
+       // Put explicitly provided properties onto the event object
+       if ( props ) {
+               jQuery.extend( this, props );
+       }
+
+       // Create a timestamp if incoming event doesn't have one
+       this.timeStamp = src && src.timeStamp || Date.now();
+
+       // Mark it as fixed
+       this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+       constructor: jQuery.Event,
+       isDefaultPrevented: returnFalse,
+       isPropagationStopped: returnFalse,
+       isImmediatePropagationStopped: returnFalse,
+       isSimulated: false,
+
+       preventDefault: function() {
+               var e = this.originalEvent;
+
+               this.isDefaultPrevented = returnTrue;
+
+               if ( e && !this.isSimulated ) {
+                       e.preventDefault();
+               }
+       },
+       stopPropagation: function() {
+               var e = this.originalEvent;
+
+               this.isPropagationStopped = returnTrue;
+
+               if ( e && !this.isSimulated ) {
+                       e.stopPropagation();
+               }
+       },
+       stopImmediatePropagation: function() {
+               var e = this.originalEvent;
+
+               this.isImmediatePropagationStopped = returnTrue;
+
+               if ( e && !this.isSimulated ) {
+                       e.stopImmediatePropagation();
+               }
+
+               this.stopPropagation();
+       }
+};
+
+// Includes all common event props including KeyEvent and MouseEvent specific props
+jQuery.each( {
+       altKey: true,
+       bubbles: true,
+       cancelable: true,
+       changedTouches: true,
+       ctrlKey: true,
+       detail: true,
+       eventPhase: true,
+       metaKey: true,
+       pageX: true,
+       pageY: true,
+       shiftKey: true,
+       view: true,
+       "char": true,
+       code: true,
+       charCode: true,
+       key: true,
+       keyCode: true,
+       button: true,
+       buttons: true,
+       clientX: true,
+       clientY: true,
+       offsetX: true,
+       offsetY: true,
+       pointerId: true,
+       pointerType: true,
+       screenX: true,
+       screenY: true,
+       targetTouches: true,
+       toElement: true,
+       touches: true,
+
+       which: function( event ) {
+               var button = event.button;
+
+               // Add which for key events
+               if ( event.which == null && rkeyEvent.test( event.type ) ) {
+                       return event.charCode != null ? event.charCode : event.keyCode;
+               }
+
+               // Add which for click: 1 === left; 2 === middle; 3 === right
+               if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
+                       if ( button & 1 ) {
+                               return 1;
+                       }
+
+                       if ( button & 2 ) {
+                               return 3;
+                       }
+
+                       if ( button & 4 ) {
+                               return 2;
+                       }
+
+                       return 0;
+               }
+
+               return event.which;
+       }
+}, jQuery.event.addProp );
+
+jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
+       jQuery.event.special[ type ] = {
+
+               // Utilize native event if possible so blur/focus sequence is correct
+               setup: function() {
+
+                       // Claim the first handler
+                       // dataPriv.set( this, "focus", ... )
+                       // dataPriv.set( this, "blur", ... )
+                       leverageNative( this, type, expectSync );
+
+                       // Return false to allow normal processing in the caller
+                       return false;
+               },
+               trigger: function() {
+
+                       // Force setup before trigger
+                       leverageNative( this, type );
+
+                       // Return non-false to allow normal event-path propagation
+                       return true;
+               },
+
+               delegateType: delegateType
+       };
+} );
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// so that event delegation works in jQuery.
+// Do the same for pointerenter/pointerleave and pointerover/pointerout
+//
+// Support: Safari 7 only
+// Safari sends mouseenter too often; see:
+// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
+// for the description of the bug (it existed in older Chrome versions as well).
+jQuery.each( {
+       mouseenter: "mouseover",
+       mouseleave: "mouseout",
+       pointerenter: "pointerover",
+       pointerleave: "pointerout"
+}, function( orig, fix ) {
+       jQuery.event.special[ orig ] = {
+               delegateType: fix,
+               bindType: fix,
+
+               handle: function( event ) {
+                       var ret,
+                               target = this,
+                               related = event.relatedTarget,
+                               handleObj = event.handleObj;
+
+                       // For mouseenter/leave call the handler if related is outside the target.
+                       // NB: No relatedTarget if the mouse left/entered the browser window
+                       if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
+                               event.type = handleObj.origType;
+                               ret = handleObj.handler.apply( this, arguments );
+                               event.type = fix;
+                       }
+                       return ret;
+               }
+       };
+} );
+
+jQuery.fn.extend( {
+
+       on: function( types, selector, data, fn ) {
+               return on( this, types, selector, data, fn );
+       },
+       one: function( types, selector, data, fn ) {
+               return on( this, types, selector, data, fn, 1 );
+       },
+       off: function( types, selector, fn ) {
+               var handleObj, type;
+               if ( types && types.preventDefault && types.handleObj ) {
+
+                       // ( event )  dispatched jQuery.Event
+                       handleObj = types.handleObj;
+                       jQuery( types.delegateTarget ).off(
+                               handleObj.namespace ?
+                                       handleObj.origType + "." + handleObj.namespace :
+                                       handleObj.origType,
+                               handleObj.selector,
+                               handleObj.handler
+                       );
+                       return this;
+               }
+               if ( typeof types === "object" ) {
+
+                       // ( types-object [, selector] )
+                       for ( type in types ) {
+                               this.off( type, selector, types[ type ] );
+                       }
+                       return this;
+               }
+               if ( selector === false || typeof selector === "function" ) {
+
+                       // ( types [, fn] )
+                       fn = selector;
+                       selector = undefined;
+               }
+               if ( fn === false ) {
+                       fn = returnFalse;
+               }
+               return this.each( function() {
+                       jQuery.event.remove( this, types, fn, selector );
+               } );
+       }
+} );
+
+
+var
+
+       // Support: IE <=10 - 11, Edge 12 - 13 only
+       // In IE/Edge using regex groups here causes severe slowdowns.
+       // See https://connect.microsoft.com/IE/feedback/details/1736512/
+       rnoInnerhtml = /<script|<style|<link/i,
+
+       // checked="checked" or checked
+       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+       rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+
+// Prefer a tbody over its parent table for containing new rows
+function manipulationTarget( elem, content ) {
+       if ( nodeName( elem, "table" ) &&
+               nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
+
+               return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
+       }
+
+       return elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+       elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
+       return elem;
+}
+function restoreScript( elem ) {
+       if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
+               elem.type = elem.type.slice( 5 );
+       } else {
+               elem.removeAttribute( "type" );
+       }
+
+       return elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+       var i, l, type, pdataOld, udataOld, udataCur, events;
+
+       if ( dest.nodeType !== 1 ) {
+               return;
+       }
+
+       // 1. Copy private data: events, handlers, etc.
+       if ( dataPriv.hasData( src ) ) {
+               pdataOld = dataPriv.get( src );
+               events = pdataOld.events;
+
+               if ( events ) {
+                       dataPriv.remove( dest, "handle events" );
+
+                       for ( type in events ) {
+                               for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+                                       jQuery.event.add( dest, type, events[ type ][ i ] );
+                               }
+                       }
+               }
+       }
+
+       // 2. Copy user data
+       if ( dataUser.hasData( src ) ) {
+               udataOld = dataUser.access( src );
+               udataCur = jQuery.extend( {}, udataOld );
+
+               dataUser.set( dest, udataCur );
+       }
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+       var nodeName = dest.nodeName.toLowerCase();
+
+       // Fails to persist the checked state of a cloned checkbox or radio button.
+       if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+               dest.checked = src.checked;
+
+       // Fails to return the selected option to the default selected state when cloning options
+       } else if ( nodeName === "input" || nodeName === "textarea" ) {
+               dest.defaultValue = src.defaultValue;
+       }
+}
+
+function domManip( collection, args, callback, ignored ) {
+
+       // Flatten any nested arrays
+       args = flat( args );
+
+       var fragment, first, scripts, hasScripts, node, doc,
+               i = 0,
+               l = collection.length,
+               iNoClone = l - 1,
+               value = args[ 0 ],
+               valueIsFunction = isFunction( value );
+
+       // We can't cloneNode fragments that contain checked, in WebKit
+       if ( valueIsFunction ||
+                       ( l > 1 && typeof value === "string" &&
+                               !support.checkClone && rchecked.test( value ) ) ) {
+               return collection.each( function( index ) {
+                       var self = collection.eq( index );
+                       if ( valueIsFunction ) {
+                               args[ 0 ] = value.call( this, index, self.html() );
+                       }
+                       domManip( self, args, callback, ignored );
+               } );
+       }
+
+       if ( l ) {
+               fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+               first = fragment.firstChild;
+
+               if ( fragment.childNodes.length === 1 ) {
+                       fragment = first;
+               }
+
+               // Require either new content or an interest in ignored elements to invoke the callback
+               if ( first || ignored ) {
+                       scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+                       hasScripts = scripts.length;
+
+                       // Use the original fragment for the last item
+                       // instead of the first because it can end up
+                       // being emptied incorrectly in certain situations (#8070).
+                       for ( ; i < l; i++ ) {
+                               node = fragment;
+
+                               if ( i !== iNoClone ) {
+                                       node = jQuery.clone( node, true, true );
+
+                                       // Keep references to cloned scripts for later restoration
+                                       if ( hasScripts ) {
+
+                                               // Support: Android <=4.0 only, PhantomJS 1 only
+                                               // push.apply(_, arraylike) throws on ancient WebKit
+                                               jQuery.merge( scripts, getAll( node, "script" ) );
+                                       }
+                               }
+
+                               callback.call( collection[ i ], node, i );
+                       }
+
+                       if ( hasScripts ) {
+                               doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+                               // Reenable scripts
+                               jQuery.map( scripts, restoreScript );
+
+                               // Evaluate executable scripts on first document insertion
+                               for ( i = 0; i < hasScripts; i++ ) {
+                                       node = scripts[ i ];
+                                       if ( rscriptType.test( node.type || "" ) &&
+                                               !dataPriv.access( node, "globalEval" ) &&
+                                               jQuery.contains( doc, node ) ) {
+
+                                               if ( node.src && ( node.type || "" ).toLowerCase()  !== "module" ) {
+
+                                                       // Optional AJAX dependency, but won't run scripts if not present
+                                                       if ( jQuery._evalUrl && !node.noModule ) {
+                                                               jQuery._evalUrl( node.src, {
+                                                                       nonce: node.nonce || node.getAttribute( "nonce" )
+                                                               }, doc );
+                                                       }
+                                               } else {
+                                                       DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return collection;
+}
+
+function remove( elem, selector, keepData ) {
+       var node,
+               nodes = selector ? jQuery.filter( selector, elem ) : elem,
+               i = 0;
+
+       for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+               if ( !keepData && node.nodeType === 1 ) {
+                       jQuery.cleanData( getAll( node ) );
+               }
+
+               if ( node.parentNode ) {
+                       if ( keepData && isAttached( node ) ) {
+                               setGlobalEval( getAll( node, "script" ) );
+                       }
+                       node.parentNode.removeChild( node );
+               }
+       }
+
+       return elem;
+}
+
+jQuery.extend( {
+       htmlPrefilter: function( html ) {
+               return html;
+       },
+
+       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+               var i, l, srcElements, destElements,
+                       clone = elem.cloneNode( true ),
+                       inPage = isAttached( elem );
+
+               // Fix IE cloning issues
+               if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+                               !jQuery.isXMLDoc( elem ) ) {
+
+                       // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
+                       destElements = getAll( clone );
+                       srcElements = getAll( elem );
+
+                       for ( i = 0, l = srcElements.length; i < l; i++ ) {
+                               fixInput( srcElements[ i ], destElements[ i ] );
+                       }
+               }
+
+               // Copy the events from the original to the clone
+               if ( dataAndEvents ) {
+                       if ( deepDataAndEvents ) {
+                               srcElements = srcElements || getAll( elem );
+                               destElements = destElements || getAll( clone );
+
+                               for ( i = 0, l = srcElements.length; i < l; i++ ) {
+                                       cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+                               }
+                       } else {
+                               cloneCopyEvent( elem, clone );
+                       }
+               }
+
+               // Preserve script evaluation history
+               destElements = getAll( clone, "script" );
+               if ( destElements.length > 0 ) {
+                       setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+               }
+
+               // Return the cloned set
+               return clone;
+       },
+
+       cleanData: function( elems ) {
+               var data, elem, type,
+                       special = jQuery.event.special,
+                       i = 0;
+
+               for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+                       if ( acceptData( elem ) ) {
+                               if ( ( data = elem[ dataPriv.expando ] ) ) {
+                                       if ( data.events ) {
+                                               for ( type in data.events ) {
+                                                       if ( special[ type ] ) {
+                                                               jQuery.event.remove( elem, type );
+
+                                                       // This is a shortcut to avoid jQuery.event.remove's overhead
+                                                       } else {
+                                                               jQuery.removeEvent( elem, type, data.handle );
+                                                       }
+                                               }
+                                       }
+
+                                       // Support: Chrome <=35 - 45+
+                                       // Assign undefined instead of using delete, see Data#remove
+                                       elem[ dataPriv.expando ] = undefined;
+                               }
+                               if ( elem[ dataUser.expando ] ) {
+
+                                       // Support: Chrome <=35 - 45+
+                                       // Assign undefined instead of using delete, see Data#remove
+                                       elem[ dataUser.expando ] = undefined;
+                               }
+                       }
+               }
+       }
+} );
+
+jQuery.fn.extend( {
+       detach: function( selector ) {
+               return remove( this, selector, true );
+       },
+
+       remove: function( selector ) {
+               return remove( this, selector );
+       },
+
+       text: function( value ) {
+               return access( this, function( value ) {
+                       return value === undefined ?
+                               jQuery.text( this ) :
+                               this.empty().each( function() {
+                                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                                               this.textContent = value;
+                                       }
+                               } );
+               }, null, value, arguments.length );
+       },
+
+       append: function() {
+               return domManip( this, arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.appendChild( elem );
+                       }
+               } );
+       },
+
+       prepend: function() {
+               return domManip( this, arguments, function( elem ) {
+                       if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+                               var target = manipulationTarget( this, elem );
+                               target.insertBefore( elem, target.firstChild );
+                       }
+               } );
+       },
+
+       before: function() {
+               return domManip( this, arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this );
+                       }
+               } );
+       },
+
+       after: function() {
+               return domManip( this, arguments, function( elem ) {
+                       if ( this.parentNode ) {
+                               this.parentNode.insertBefore( elem, this.nextSibling );
+                       }
+               } );
+       },
+
+       empty: function() {
+               var elem,
+                       i = 0;
+
+               for ( ; ( elem = this[ i ] ) != null; i++ ) {
+                       if ( elem.nodeType === 1 ) {
+
+                               // Prevent memory leaks
+                               jQuery.cleanData( getAll( elem, false ) );
+
+                               // Remove any remaining nodes
+                               elem.textContent = "";
+                       }
+               }
+
+               return this;
+       },
+
+       clone: function( dataAndEvents, deepDataAndEvents ) {
+               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+               return this.map( function() {
+                       return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+               } );
+       },
+
+       html: function( value ) {
+               return access( this, function( value ) {
+                       var elem = this[ 0 ] || {},
+                               i = 0,
+                               l = this.length;
+
+                       if ( value === undefined && elem.nodeType === 1 ) {
+                               return elem.innerHTML;
+                       }
+
+                       // See if we can take a shortcut and just use innerHTML
+                       if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+                               !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+                               value = jQuery.htmlPrefilter( value );
+
+                               try {
+                                       for ( ; i < l; i++ ) {
+                                               elem = this[ i ] || {};
+
+                                               // Remove element nodes and prevent memory leaks
+                                               if ( elem.nodeType === 1 ) {
+                                                       jQuery.cleanData( getAll( elem, false ) );
+                                                       elem.innerHTML = value;
+                                               }
+                                       }
+
+                                       elem = 0;
+
+                               // If using innerHTML throws an exception, use the fallback method
+                               } catch ( e ) {}
+                       }
+
+                       if ( elem ) {
+                               this.empty().append( value );
+                       }
+               }, null, value, arguments.length );
+       },
+
+       replaceWith: function() {
+               var ignored = [];
+
+               // Make the changes, replacing each non-ignored context element with the new content
+               return domManip( this, arguments, function( elem ) {
+                       var parent = this.parentNode;
+
+                       if ( jQuery.inArray( this, ignored ) < 0 ) {
+                               jQuery.cleanData( getAll( this ) );
+                               if ( parent ) {
+                                       parent.replaceChild( elem, this );
+                               }
+                       }
+
+               // Force callback invocation
+               }, ignored );
+       }
+} );
+
+jQuery.each( {
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function( name, original ) {
+       jQuery.fn[ name ] = function( selector ) {
+               var elems,
+                       ret = [],
+                       insert = jQuery( selector ),
+                       last = insert.length - 1,
+                       i = 0;
+
+               for ( ; i <= last; i++ ) {
+                       elems = i === last ? this : this.clone( true );
+                       jQuery( insert[ i ] )[ original ]( elems );
+
+                       // Support: Android <=4.0 only, PhantomJS 1 only
+                       // .get() because push.apply(_, arraylike) throws on ancient WebKit
+                       push.apply( ret, elems.get() );
+               }
+
+               return this.pushStack( ret );
+       };
+} );
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+
+               // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
+               // IE throws on elements created in popups
+               // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+               var view = elem.ownerDocument.defaultView;
+
+               if ( !view || !view.opener ) {
+                       view = window;
+               }
+
+               return view.getComputedStyle( elem );
+       };
+
+var swap = function( elem, options, callback ) {
+       var ret, name,
+               old = {};
+
+       // Remember the old values, and insert the new ones
+       for ( name in options ) {
+               old[ name ] = elem.style[ name ];
+               elem.style[ name ] = options[ name ];
+       }
+
+       ret = callback.call( elem );
+
+       // Revert the old values
+       for ( name in options ) {
+               elem.style[ name ] = old[ name ];
+       }
+
+       return ret;
+};
+
+
+var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
+
+
+
+( function() {
+
+       // Executing both pixelPosition & boxSizingReliable tests require only one layout
+       // so they're executed at the same time to save the second computation.
+       function computeStyleTests() {
+
+               // This is a singleton, we need to execute it only once
+               if ( !div ) {
+                       return;
+               }
+
+               container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
+                       "margin-top:1px;padding:0;border:0";
+               div.style.cssText =
+                       "position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
+                       "margin:auto;border:1px;padding:1px;" +
+                       "width:60%;top:1%";
+               documentElement.appendChild( container ).appendChild( div );
+
+               var divStyle = window.getComputedStyle( div );
+               pixelPositionVal = divStyle.top !== "1%";
+
+               // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
+               reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
+
+               // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
+               // Some styles come back with percentage values, even though they shouldn't
+               div.style.right = "60%";
+               pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
+
+               // Support: IE 9 - 11 only
+               // Detect misreporting of content dimensions for box-sizing:border-box elements
+               boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
+
+               // Support: IE 9 only
+               // Detect overflow:scroll screwiness (gh-3699)
+               // Support: Chrome <=64
+               // Don't get tricked when zoom affects offsetWidth (gh-4029)
+               div.style.position = "absolute";
+               scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
+
+               documentElement.removeChild( container );
+
+               // Nullify the div so it wouldn't be stored in the memory and
+               // it will also be a sign that checks already performed
+               div = null;
+       }
+
+       function roundPixelMeasures( measure ) {
+               return Math.round( parseFloat( measure ) );
+       }
+
+       var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
+               reliableTrDimensionsVal, reliableMarginLeftVal,
+               container = document.createElement( "div" ),
+               div = document.createElement( "div" );
+
+       // Finish early in limited (non-browser) environments
+       if ( !div.style ) {
+               return;
+       }
+
+       // Support: IE <=9 - 11 only
+       // Style of cloned element affects source element cloned (#8908)
+       div.style.backgroundClip = "content-box";
+       div.cloneNode( true ).style.backgroundClip = "";
+       support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+       jQuery.extend( support, {
+               boxSizingReliable: function() {
+                       computeStyleTests();
+                       return boxSizingReliableVal;
+               },
+               pixelBoxStyles: function() {
+                       computeStyleTests();
+                       return pixelBoxStylesVal;
+               },
+               pixelPosition: function() {
+                       computeStyleTests();
+                       return pixelPositionVal;
+               },
+               reliableMarginLeft: function() {
+                       computeStyleTests();
+                       return reliableMarginLeftVal;
+               },
+               scrollboxSize: function() {
+                       computeStyleTests();
+                       return scrollboxSizeVal;
+               },
+
+               // Support: IE 9 - 11+, Edge 15 - 18+
+               // IE/Edge misreport `getComputedStyle` of table rows with width/height
+               // set in CSS while `offset*` properties report correct values.
+               // Behavior in IE 9 is more subtle than in newer versions & it passes
+               // some versions of this test; make sure not to make it pass there!
+               reliableTrDimensions: function() {
+                       var table, tr, trChild, trStyle;
+                       if ( reliableTrDimensionsVal == null ) {
+                               table = document.createElement( "table" );
+                               tr = document.createElement( "tr" );
+                               trChild = document.createElement( "div" );
+
+                               table.style.cssText = "position:absolute;left:-11111px";
+                               tr.style.height = "1px";
+                               trChild.style.height = "9px";
+
+                               documentElement
+                                       .appendChild( table )
+                                       .appendChild( tr )
+                                       .appendChild( trChild );
+
+                               trStyle = window.getComputedStyle( tr );
+                               reliableTrDimensionsVal = parseInt( trStyle.height ) > 3;
+
+                               documentElement.removeChild( table );
+                       }
+                       return reliableTrDimensionsVal;
+               }
+       } );
+} )();
+
+
+function curCSS( elem, name, computed ) {
+       var width, minWidth, maxWidth, ret,
+
+               // Support: Firefox 51+
+               // Retrieving style before computed somehow
+               // fixes an issue with getting wrong values
+               // on detached elements
+               style = elem.style;
+
+       computed = computed || getStyles( elem );
+
+       // getPropertyValue is needed for:
+       //   .css('filter') (IE 9 only, #12537)
+       //   .css('--customProperty) (#3144)
+       if ( computed ) {
+               ret = computed.getPropertyValue( name ) || computed[ name ];
+
+               if ( ret === "" && !isAttached( elem ) ) {
+                       ret = jQuery.style( elem, name );
+               }
+
+               // A tribute to the "awesome hack by Dean Edwards"
+               // Android Browser returns percentage for some values,
+               // but width seems to be reliably pixels.
+               // This is against the CSSOM draft spec:
+               // https://drafts.csswg.org/cssom/#resolved-values
+               if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
+
+                       // Remember the original values
+                       width = style.width;
+                       minWidth = style.minWidth;
+                       maxWidth = style.maxWidth;
+
+                       // Put in the new values to get a computed value out
+                       style.minWidth = style.maxWidth = style.width = ret;
+                       ret = computed.width;
+
+                       // Revert the changed values
+                       style.width = width;
+                       style.minWidth = minWidth;
+                       style.maxWidth = maxWidth;
+               }
+       }
+
+       return ret !== undefined ?
+
+               // Support: IE <=9 - 11 only
+               // IE returns zIndex value as an integer.
+               ret + "" :
+               ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+
+       // Define the hook, we'll check on the first run if it's really needed.
+       return {
+               get: function() {
+                       if ( conditionFn() ) {
+
+                               // Hook not needed (or it's not possible to use it due
+                               // to missing dependency), remove it.
+                               delete this.get;
+                               return;
+                       }
+
+                       // Hook needed; redefine it so that the support test is not executed again.
+                       return ( this.get = hookFn ).apply( this, arguments );
+               }
+       };
+}
+
+
+var cssPrefixes = [ "Webkit", "Moz", "ms" ],
+       emptyStyle = document.createElement( "div" ).style,
+       vendorProps = {};
+
+// Return a vendor-prefixed property or undefined
+function vendorPropName( name ) {
+
+       // Check for vendor prefixed names
+       var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
+               i = cssPrefixes.length;
+
+       while ( i-- ) {
+               name = cssPrefixes[ i ] + capName;
+               if ( name in emptyStyle ) {
+                       return name;
+               }
+       }
+}
+
+// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
+function finalPropName( name ) {
+       var final = jQuery.cssProps[ name ] || vendorProps[ name ];
+
+       if ( final ) {
+               return final;
+       }
+       if ( name in emptyStyle ) {
+               return name;
+       }
+       return vendorProps[ name ] = vendorPropName( name ) || name;
+}
+
+
+var
+
+       // Swappable if display is none or starts with table
+       // except "table", "table-cell", or "table-caption"
+       // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+       rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+       rcustomProp = /^--/,
+       cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+       cssNormalTransform = {
+               letterSpacing: "0",
+               fontWeight: "400"
+       };
+
+function setPositiveNumber( _elem, value, subtract ) {
+
+       // Any relative (+/-) values have already been
+       // normalized at this point
+       var matches = rcssNum.exec( value );
+       return matches ?
+
+               // Guard against undefined "subtract", e.g., when used as in cssHooks
+               Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
+               value;
+}
+
+function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
+       var i = dimension === "width" ? 1 : 0,
+               extra = 0,
+               delta = 0;
+
+       // Adjustment may not be necessary
+       if ( box === ( isBorderBox ? "border" : "content" ) ) {
+               return 0;
+       }
+
+       for ( ; i < 4; i += 2 ) {
+
+               // Both box models exclude margin
+               if ( box === "margin" ) {
+                       delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
+               }
+
+               // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
+               if ( !isBorderBox ) {
+
+                       // Add padding
+                       delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+                       // For "border" or "margin", add border
+                       if ( box !== "padding" ) {
+                               delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+
+                       // But still keep track of it otherwise
+                       } else {
+                               extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+
+               // If we get here with a border-box (content + padding + border), we're seeking "content" or
+               // "padding" or "margin"
+               } else {
+
+                       // For "content", subtract padding
+                       if ( box === "content" ) {
+                               delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+                       }
+
+                       // For "content" or "padding", subtract border
+                       if ( box !== "margin" ) {
+                               delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+                       }
+               }
+       }
+
+       // Account for positive content-box scroll gutter when requested by providing computedVal
+       if ( !isBorderBox && computedVal >= 0 ) {
+
+               // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
+               // Assuming integer scroll gutter, subtract the rest and round down
+               delta += Math.max( 0, Math.ceil(
+                       elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+                       computedVal -
+                       delta -
+                       extra -
+                       0.5
+
+               // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
+               // Use an explicit zero to avoid NaN (gh-3964)
+               ) ) || 0;
+       }
+
+       return delta;
+}
+
+function getWidthOrHeight( elem, dimension, extra ) {
+
+       // Start with computed style
+       var styles = getStyles( elem ),
+
+               // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
+               // Fake content-box until we know it's needed to know the true value.
+               boxSizingNeeded = !support.boxSizingReliable() || extra,
+               isBorderBox = boxSizingNeeded &&
+                       jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+               valueIsBorderBox = isBorderBox,
+
+               val = curCSS( elem, dimension, styles ),
+               offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
+
+       // Support: Firefox <=54
+       // Return a confounding non-pixel value or feign ignorance, as appropriate.
+       if ( rnumnonpx.test( val ) ) {
+               if ( !extra ) {
+                       return val;
+               }
+               val = "auto";
+       }
+
+
+       // Support: IE 9 - 11 only
+       // Use offsetWidth/offsetHeight for when box sizing is unreliable.
+       // In those cases, the computed value can be trusted to be border-box.
+       if ( ( !support.boxSizingReliable() && isBorderBox ||
+
+               // Support: IE 10 - 11+, Edge 15 - 18+
+               // IE/Edge misreport `getComputedStyle` of table rows with width/height
+               // set in CSS while `offset*` properties report correct values.
+               // Interestingly, in some cases IE 9 doesn't suffer from this issue.
+               !support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
+
+               // Fall back to offsetWidth/offsetHeight when value is "auto"
+               // This happens for inline elements with no explicit setting (gh-3571)
+               val === "auto" ||
+
+               // Support: Android <=4.1 - 4.3 only
+               // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
+               !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
+
+               // Make sure the element is visible & connected
+               elem.getClientRects().length ) {
+
+               isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+               // Where available, offsetWidth/offsetHeight approximate border box dimensions.
+               // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
+               // retrieved value as a content box dimension.
+               valueIsBorderBox = offsetProp in elem;
+               if ( valueIsBorderBox ) {
+                       val = elem[ offsetProp ];
+               }
+       }
+
+       // Normalize "" and auto
+       val = parseFloat( val ) || 0;
+
+       // Adjust for the element's box model
+       return ( val +
+               boxModelAdjustment(
+                       elem,
+                       dimension,
+                       extra || ( isBorderBox ? "border" : "content" ),
+                       valueIsBorderBox,
+                       styles,
+
+                       // Provide the current computed size to request scroll gutter calculation (gh-3589)
+                       val
+               )
+       ) + "px";
+}
+
+jQuery.extend( {
+
+       // Add in style property hooks for overriding the default
+       // behavior of getting and setting a style property
+       cssHooks: {
+               opacity: {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+
+                                       // We should always get a number back from opacity
+                                       var ret = curCSS( elem, "opacity" );
+                                       return ret === "" ? "1" : ret;
+                               }
+                       }
+               }
+       },
+
+       // Don't automatically add "px" to these possibly-unitless properties
+       cssNumber: {
+               "animationIterationCount": true,
+               "columnCount": true,
+               "fillOpacity": true,
+               "flexGrow": true,
+               "flexShrink": true,
+               "fontWeight": true,
+               "gridArea": true,
+               "gridColumn": true,
+               "gridColumnEnd": true,
+               "gridColumnStart": true,
+               "gridRow": true,
+               "gridRowEnd": true,
+               "gridRowStart": true,
+               "lineHeight": true,
+               "opacity": true,
+               "order": true,
+               "orphans": true,
+               "widows": true,
+               "zIndex": true,
+               "zoom": true
+       },
+
+       // Add in properties whose names you wish to fix before
+       // setting or getting the value
+       cssProps: {},
+
+       // Get and set the style property on a DOM Node
+       style: function( elem, name, value, extra ) {
+
+               // Don't set styles on text and comment nodes
+               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+                       return;
+               }
+
+               // Make sure that we're working with the right name
+               var ret, type, hooks,
+                       origName = camelCase( name ),
+                       isCustomProp = rcustomProp.test( name ),
+                       style = elem.style;
+
+               // Make sure that we're working with the right name. We don't
+               // want to query the value if it is a CSS custom property
+               // since they are user-defined.
+               if ( !isCustomProp ) {
+                       name = finalPropName( origName );
+               }
+
+               // Gets hook for the prefixed version, then unprefixed version
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // Check if we're setting a value
+               if ( value !== undefined ) {
+                       type = typeof value;
+
+                       // Convert "+=" or "-=" to relative numbers (#7345)
+                       if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+                               value = adjustCSS( elem, name, ret );
+
+                               // Fixes bug #9237
+                               type = "number";
+                       }
+
+                       // Make sure that null and NaN values aren't set (#7116)
+                       if ( value == null || value !== value ) {
+                               return;
+                       }
+
+                       // If a number was passed in, add the unit (except for certain CSS properties)
+                       // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
+                       // "px" to a few hardcoded values.
+                       if ( type === "number" && !isCustomProp ) {
+                               value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
+                       }
+
+                       // background-* props affect original clone's values
+                       if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+                               style[ name ] = "inherit";
+                       }
+
+                       // If a hook was provided, use that value, otherwise just set the specified value
+                       if ( !hooks || !( "set" in hooks ) ||
+                               ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
+
+                               if ( isCustomProp ) {
+                                       style.setProperty( name, value );
+                               } else {
+                                       style[ name ] = value;
+                               }
+                       }
+
+               } else {
+
+                       // If a hook was provided get the non-computed value from there
+                       if ( hooks && "get" in hooks &&
+                               ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
+
+                               return ret;
+                       }
+
+                       // Otherwise just get the value from the style object
+                       return style[ name ];
+               }
+       },
+
+       css: function( elem, name, extra, styles ) {
+               var val, num, hooks,
+                       origName = camelCase( name ),
+                       isCustomProp = rcustomProp.test( name );
+
+               // Make sure that we're working with the right name. We don't
+               // want to modify the value if it is a CSS custom property
+               // since they are user-defined.
+               if ( !isCustomProp ) {
+                       name = finalPropName( origName );
+               }
+
+               // Try prefixed name followed by the unprefixed name
+               hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+               // If a hook was provided get the computed value from there
+               if ( hooks && "get" in hooks ) {
+                       val = hooks.get( elem, true, extra );
+               }
+
+               // Otherwise, if a way to get the computed value exists, use that
+               if ( val === undefined ) {
+                       val = curCSS( elem, name, styles );
+               }
+
+               // Convert "normal" to computed value
+               if ( val === "normal" && name in cssNormalTransform ) {
+                       val = cssNormalTransform[ name ];
+               }
+
+               // Make numeric if forced or a qualifier was provided and val looks numeric
+               if ( extra === "" || extra ) {
+                       num = parseFloat( val );
+                       return extra === true || isFinite( num ) ? num || 0 : val;
+               }
+
+               return val;
+       }
+} );
+
+jQuery.each( [ "height", "width" ], function( _i, dimension ) {
+       jQuery.cssHooks[ dimension ] = {
+               get: function( elem, computed, extra ) {
+                       if ( computed ) {
+
+                               // Certain elements can have dimension info if we invisibly show them
+                               // but it must have a current display style that would benefit
+                               return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+
+                                       // Support: Safari 8+
+                                       // Table columns in Safari have non-zero offsetWidth & zero
+                                       // getBoundingClientRect().width unless display is changed.
+                                       // Support: IE <=11 only
+                                       // Running getBoundingClientRect on a disconnected node
+                                       // in IE throws an error.
+                                       ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
+                                               swap( elem, cssShow, function() {
+                                                       return getWidthOrHeight( elem, dimension, extra );
+                                               } ) :
+                                               getWidthOrHeight( elem, dimension, extra );
+                       }
+               },
+
+               set: function( elem, value, extra ) {
+                       var matches,
+                               styles = getStyles( elem ),
+
+                               // Only read styles.position if the test has a chance to fail
+                               // to avoid forcing a reflow.
+                               scrollboxSizeBuggy = !support.scrollboxSize() &&
+                                       styles.position === "absolute",
+
+                               // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
+                               boxSizingNeeded = scrollboxSizeBuggy || extra,
+                               isBorderBox = boxSizingNeeded &&
+                                       jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+                               subtract = extra ?
+                                       boxModelAdjustment(
+                                               elem,
+                                               dimension,
+                                               extra,
+                                               isBorderBox,
+                                               styles
+                                       ) :
+                                       0;
+
+                       // Account for unreliable border-box dimensions by comparing offset* to computed and
+                       // faking a content-box to get border and padding (gh-3699)
+                       if ( isBorderBox && scrollboxSizeBuggy ) {
+                               subtract -= Math.ceil(
+                                       elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+                                       parseFloat( styles[ dimension ] ) -
+                                       boxModelAdjustment( elem, dimension, "border", false, styles ) -
+                                       0.5
+                               );
+                       }
+
+                       // Convert to pixels if value adjustment is needed
+                       if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+                               ( matches[ 3 ] || "px" ) !== "px" ) {
+
+                               elem.style[ dimension ] = value;
+                               value = jQuery.css( elem, dimension );
+                       }
+
+                       return setPositiveNumber( elem, value, subtract );
+               }
+       };
+} );
+
+jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
+       function( elem, computed ) {
+               if ( computed ) {
+                       return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+                               elem.getBoundingClientRect().left -
+                                       swap( elem, { marginLeft: 0 }, function() {
+                                               return elem.getBoundingClientRect().left;
+                                       } )
+                               ) + "px";
+               }
+       }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each( {
+       margin: "",
+       padding: "",
+       border: "Width"
+}, function( prefix, suffix ) {
+       jQuery.cssHooks[ prefix + suffix ] = {
+               expand: function( value ) {
+                       var i = 0,
+                               expanded = {},
+
+                               // Assumes a single number if not a string
+                               parts = typeof value === "string" ? value.split( " " ) : [ value ];
+
+                       for ( ; i < 4; i++ ) {
+                               expanded[ prefix + cssExpand[ i ] + suffix ] =
+                                       parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+                       }
+
+                       return expanded;
+               }
+       };
+
+       if ( prefix !== "margin" ) {
+               jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+       }
+} );
+
+jQuery.fn.extend( {
+       css: function( name, value ) {
+               return access( this, function( elem, name, value ) {
+                       var styles, len,
+                               map = {},
+                               i = 0;
+
+                       if ( Array.isArray( name ) ) {
+                               styles = getStyles( elem );
+                               len = name.length;
+
+                               for ( ; i < len; i++ ) {
+                                       map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+                               }
+
+                               return map;
+                       }
+
+                       return value !== undefined ?
+                               jQuery.style( elem, name, value ) :
+                               jQuery.css( elem, name );
+               }, name, value, arguments.length > 1 );
+       }
+} );
+
+
+function Tween( elem, options, prop, end, easing ) {
+       return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+       constructor: Tween,
+       init: function( elem, options, prop, end, easing, unit ) {
+               this.elem = elem;
+               this.prop = prop;
+               this.easing = easing || jQuery.easing._default;
+               this.options = options;
+               this.start = this.now = this.cur();
+               this.end = end;
+               this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+       },
+       cur: function() {
+               var hooks = Tween.propHooks[ this.prop ];
+
+               return hooks && hooks.get ?
+                       hooks.get( this ) :
+                       Tween.propHooks._default.get( this );
+       },
+       run: function( percent ) {
+               var eased,
+                       hooks = Tween.propHooks[ this.prop ];
+
+               if ( this.options.duration ) {
+                       this.pos = eased = jQuery.easing[ this.easing ](
+                               percent, this.options.duration * percent, 0, 1, this.options.duration
+                       );
+               } else {
+                       this.pos = eased = percent;
+               }
+               this.now = ( this.end - this.start ) * eased + this.start;
+
+               if ( this.options.step ) {
+                       this.options.step.call( this.elem, this.now, this );
+               }
+
+               if ( hooks && hooks.set ) {
+                       hooks.set( this );
+               } else {
+                       Tween.propHooks._default.set( this );
+               }
+               return this;
+       }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+       _default: {
+               get: function( tween ) {
+                       var result;
+
+                       // Use a property on the element directly when it is not a DOM element,
+                       // or when there is no matching style property that exists.
+                       if ( tween.elem.nodeType !== 1 ||
+                               tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
+                               return tween.elem[ tween.prop ];
+                       }
+
+                       // Passing an empty string as a 3rd parameter to .css will automatically
+                       // attempt a parseFloat and fallback to a string if the parse fails.
+                       // Simple values such as "10px" are parsed to Float;
+                       // complex values such as "rotate(1rad)" are returned as-is.
+                       result = jQuery.css( tween.elem, tween.prop, "" );
+
+                       // Empty strings, null, undefined and "auto" are converted to 0.
+                       return !result || result === "auto" ? 0 : result;
+               },
+               set: function( tween ) {
+
+                       // Use step hook for back compat.
+                       // Use cssHook if its there.
+                       // Use .style if available and use plain properties where available.
+                       if ( jQuery.fx.step[ tween.prop ] ) {
+                               jQuery.fx.step[ tween.prop ]( tween );
+                       } else if ( tween.elem.nodeType === 1 && (
+                                       jQuery.cssHooks[ tween.prop ] ||
+                                       tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
+                               jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+                       } else {
+                               tween.elem[ tween.prop ] = tween.now;
+                       }
+               }
+       }
+};
+
+// Support: IE <=9 only
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+       set: function( tween ) {
+               if ( tween.elem.nodeType && tween.elem.parentNode ) {
+                       tween.elem[ tween.prop ] = tween.now;
+               }
+       }
+};
+
+jQuery.easing = {
+       linear: function( p ) {
+               return p;
+       },
+       swing: function( p ) {
+               return 0.5 - Math.cos( p * Math.PI ) / 2;
+       },
+       _default: "swing"
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+       fxNow, inProgress,
+       rfxtypes = /^(?:toggle|show|hide)$/,
+       rrun = /queueHooks$/;
+
+function schedule() {
+       if ( inProgress ) {
+               if ( document.hidden === false && window.requestAnimationFrame ) {
+                       window.requestAnimationFrame( schedule );
+               } else {
+                       window.setTimeout( schedule, jQuery.fx.interval );
+               }
+
+               jQuery.fx.tick();
+       }
+}
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+       window.setTimeout( function() {
+               fxNow = undefined;
+       } );
+       return ( fxNow = Date.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+       var which,
+               i = 0,
+               attrs = { height: type };
+
+       // If we include width, step value is 1 to do all cssExpand values,
+       // otherwise step value is 2 to skip over Left and Right
+       includeWidth = includeWidth ? 1 : 0;
+       for ( ; i < 4; i += 2 - includeWidth ) {
+               which = cssExpand[ i ];
+               attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+       }
+
+       if ( includeWidth ) {
+               attrs.opacity = attrs.width = type;
+       }
+
+       return attrs;
+}
+
+function createTween( value, prop, animation ) {
+       var tween,
+               collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
+               index = 0,
+               length = collection.length;
+       for ( ; index < length; index++ ) {
+               if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
+
+                       // We're done with this property
+                       return tween;
+               }
+       }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+       var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+               isBox = "width" in props || "height" in props,
+               anim = this,
+               orig = {},
+               style = elem.style,
+               hidden = elem.nodeType && isHiddenWithinTree( elem ),
+               dataShow = dataPriv.get( elem, "fxshow" );
+
+       // Queue-skipping animations hijack the fx hooks
+       if ( !opts.queue ) {
+               hooks = jQuery._queueHooks( elem, "fx" );
+               if ( hooks.unqueued == null ) {
+                       hooks.unqueued = 0;
+                       oldfire = hooks.empty.fire;
+                       hooks.empty.fire = function() {
+                               if ( !hooks.unqueued ) {
+                                       oldfire();
+                               }
+                       };
+               }
+               hooks.unqueued++;
+
+               anim.always( function() {
+
+                       // Ensure the complete handler is called before this completes
+                       anim.always( function() {
+                               hooks.unqueued--;
+                               if ( !jQuery.queue( elem, "fx" ).length ) {
+                                       hooks.empty.fire();
+                               }
+                       } );
+               } );
+       }
+
+       // Detect show/hide animations
+       for ( prop in props ) {
+               value = props[ prop ];
+               if ( rfxtypes.test( value ) ) {
+                       delete props[ prop ];
+                       toggle = toggle || value === "toggle";
+                       if ( value === ( hidden ? "hide" : "show" ) ) {
+
+                               // Pretend to be hidden if this is a "show" and
+                               // there is still data from a stopped show/hide
+                               if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+                                       hidden = true;
+
+                               // Ignore all other no-op show/hide data
+                               } else {
+                                       continue;
+                               }
+                       }
+                       orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+               }
+       }
+
+       // Bail out if this is a no-op like .hide().hide()
+       propTween = !jQuery.isEmptyObject( props );
+       if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+               return;
+       }
+
+       // Restrict "overflow" and "display" styles during box animations
+       if ( isBox && elem.nodeType === 1 ) {
+
+               // Support: IE <=9 - 11, Edge 12 - 15
+               // Record all 3 overflow attributes because IE does not infer the shorthand
+               // from identically-valued overflowX and overflowY and Edge just mirrors
+               // the overflowX value there.
+               opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+               // Identify a display type, preferring old show/hide data over the CSS cascade
+               restoreDisplay = dataShow && dataShow.display;
+               if ( restoreDisplay == null ) {
+                       restoreDisplay = dataPriv.get( elem, "display" );
+               }
+               display = jQuery.css( elem, "display" );
+               if ( display === "none" ) {
+                       if ( restoreDisplay ) {
+                               display = restoreDisplay;
+                       } else {
+
+                               // Get nonempty value(s) by temporarily forcing visibility
+                               showHide( [ elem ], true );
+                               restoreDisplay = elem.style.display || restoreDisplay;
+                               display = jQuery.css( elem, "display" );
+                               showHide( [ elem ] );
+                       }
+               }
+
+               // Animate inline elements as inline-block
+               if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+                       if ( jQuery.css( elem, "float" ) === "none" ) {
+
+                               // Restore the original display value at the end of pure show/hide animations
+                               if ( !propTween ) {
+                                       anim.done( function() {
+                                               style.display = restoreDisplay;
+                                       } );
+                                       if ( restoreDisplay == null ) {
+                                               display = style.display;
+                                               restoreDisplay = display === "none" ? "" : display;
+                                       }
+                               }
+                               style.display = "inline-block";
+                       }
+               }
+       }
+
+       if ( opts.overflow ) {
+               style.overflow = "hidden";
+               anim.always( function() {
+                       style.overflow = opts.overflow[ 0 ];
+                       style.overflowX = opts.overflow[ 1 ];
+                       style.overflowY = opts.overflow[ 2 ];
+               } );
+       }
+
+       // Implement show/hide animations
+       propTween = false;
+       for ( prop in orig ) {
+
+               // General show/hide setup for this element animation
+               if ( !propTween ) {
+                       if ( dataShow ) {
+                               if ( "hidden" in dataShow ) {
+                                       hidden = dataShow.hidden;
+                               }
+                       } else {
+                               dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
+                       }
+
+                       // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+                       if ( toggle ) {
+                               dataShow.hidden = !hidden;
+                       }
+
+                       // Show elements before animating them
+                       if ( hidden ) {
+                               showHide( [ elem ], true );
+                       }
+
+                       /* eslint-disable no-loop-func */
+
+                       anim.done( function() {
+
+                       /* eslint-enable no-loop-func */
+
+                               // The final step of a "hide" animation is actually hiding the element
+                               if ( !hidden ) {
+                                       showHide( [ elem ] );
+                               }
+                               dataPriv.remove( elem, "fxshow" );
+                               for ( prop in orig ) {
+                                       jQuery.style( elem, prop, orig[ prop ] );
+                               }
+                       } );
+               }
+
+               // Per-property setup
+               propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+               if ( !( prop in dataShow ) ) {
+                       dataShow[ prop ] = propTween.start;
+                       if ( hidden ) {
+                               propTween.end = propTween.start;
+                               propTween.start = 0;
+                       }
+               }
+       }
+}
+
+function propFilter( props, specialEasing ) {
+       var index, name, easing, value, hooks;
+
+       // camelCase, specialEasing and expand cssHook pass
+       for ( index in props ) {
+               name = camelCase( index );
+               easing = specialEasing[ name ];
+               value = props[ index ];
+               if ( Array.isArray( value ) ) {
+                       easing = value[ 1 ];
+                       value = props[ index ] = value[ 0 ];
+               }
+
+               if ( index !== name ) {
+                       props[ name ] = value;
+                       delete props[ index ];
+               }
+
+               hooks = jQuery.cssHooks[ name ];
+               if ( hooks && "expand" in hooks ) {
+                       value = hooks.expand( value );
+                       delete props[ name ];
+
+                       // Not quite $.extend, this won't overwrite existing keys.
+                       // Reusing 'index' because we have the correct "name"
+                       for ( index in value ) {
+                               if ( !( index in props ) ) {
+                                       props[ index ] = value[ index ];
+                                       specialEasing[ index ] = easing;
+                               }
+                       }
+               } else {
+                       specialEasing[ name ] = easing;
+               }
+       }
+}
+
+function Animation( elem, properties, options ) {
+       var result,
+               stopped,
+               index = 0,
+               length = Animation.prefilters.length,
+               deferred = jQuery.Deferred().always( function() {
+
+                       // Don't match elem in the :animated selector
+                       delete tick.elem;
+               } ),
+               tick = function() {
+                       if ( stopped ) {
+                               return false;
+                       }
+                       var currentTime = fxNow || createFxNow(),
+                               remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+
+                               // Support: Android 2.3 only
+                               // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+                               temp = remaining / animation.duration || 0,
+                               percent = 1 - temp,
+                               index = 0,
+                               length = animation.tweens.length;
+
+                       for ( ; index < length; index++ ) {
+                               animation.tweens[ index ].run( percent );
+                       }
+
+                       deferred.notifyWith( elem, [ animation, percent, remaining ] );
+
+                       // If there's more to do, yield
+                       if ( percent < 1 && length ) {
+                               return remaining;
+                       }
+
+                       // If this was an empty animation, synthesize a final progress notification
+                       if ( !length ) {
+                               deferred.notifyWith( elem, [ animation, 1, 0 ] );
+                       }
+
+                       // Resolve the animation and report its conclusion
+                       deferred.resolveWith( elem, [ animation ] );
+                       return false;
+               },
+               animation = deferred.promise( {
+                       elem: elem,
+                       props: jQuery.extend( {}, properties ),
+                       opts: jQuery.extend( true, {
+                               specialEasing: {},
+                               easing: jQuery.easing._default
+                       }, options ),
+                       originalProperties: properties,
+                       originalOptions: options,
+                       startTime: fxNow || createFxNow(),
+                       duration: options.duration,
+                       tweens: [],
+                       createTween: function( prop, end ) {
+                               var tween = jQuery.Tween( elem, animation.opts, prop, end,
+                                               animation.opts.specialEasing[ prop ] || animation.opts.easing );
+                               animation.tweens.push( tween );
+                               return tween;
+                       },
+                       stop: function( gotoEnd ) {
+                               var index = 0,
+
+                                       // If we are going to the end, we want to run all the tweens
+                                       // otherwise we skip this part
+                                       length = gotoEnd ? animation.tweens.length : 0;
+                               if ( stopped ) {
+                                       return this;
+                               }
+                               stopped = true;
+                               for ( ; index < length; index++ ) {
+                                       animation.tweens[ index ].run( 1 );
+                               }
+
+                               // Resolve when we played the last frame; otherwise, reject
+                               if ( gotoEnd ) {
+                                       deferred.notifyWith( elem, [ animation, 1, 0 ] );
+                                       deferred.resolveWith( elem, [ animation, gotoEnd ] );
+                               } else {
+                                       deferred.rejectWith( elem, [ animation, gotoEnd ] );
+                               }
+                               return this;
+                       }
+               } ),
+               props = animation.props;
+
+       propFilter( props, animation.opts.specialEasing );
+
+       for ( ; index < length; index++ ) {
+               result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
+               if ( result ) {
+                       if ( isFunction( result.stop ) ) {
+                               jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+                                       result.stop.bind( result );
+                       }
+                       return result;
+               }
+       }
+
+       jQuery.map( props, createTween, animation );
+
+       if ( isFunction( animation.opts.start ) ) {
+               animation.opts.start.call( elem, animation );
+       }
+
+       // Attach callbacks from options
+       animation
+               .progress( animation.opts.progress )
+               .done( animation.opts.done, animation.opts.complete )
+               .fail( animation.opts.fail )
+               .always( animation.opts.always );
+
+       jQuery.fx.timer(
+               jQuery.extend( tick, {
+                       elem: elem,
+                       anim: animation,
+                       queue: animation.opts.queue
+               } )
+       );
+
+       return animation;
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+       tweeners: {
+               "*": [ function( prop, value ) {
+                       var tween = this.createTween( prop, value );
+                       adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+                       return tween;
+               } ]
+       },
+
+       tweener: function( props, callback ) {
+               if ( isFunction( props ) ) {
+                       callback = props;
+                       props = [ "*" ];
+               } else {
+                       props = props.match( rnothtmlwhite );
+               }
+
+               var prop,
+                       index = 0,
+                       length = props.length;
+
+               for ( ; index < length; index++ ) {
+                       prop = props[ index ];
+                       Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+                       Animation.tweeners[ prop ].unshift( callback );
+               }
+       },
+
+       prefilters: [ defaultPrefilter ],
+
+       prefilter: function( callback, prepend ) {
+               if ( prepend ) {
+                       Animation.prefilters.unshift( callback );
+               } else {
+                       Animation.prefilters.push( callback );
+               }
+       }
+} );
+
+jQuery.speed = function( speed, easing, fn ) {
+       var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+               complete: fn || !fn && easing ||
+                       isFunction( speed ) && speed,
+               duration: speed,
+               easing: fn && easing || easing && !isFunction( easing ) && easing
+       };
+
+       // Go to the end state if fx are off
+       if ( jQuery.fx.off ) {
+               opt.duration = 0;
+
+       } else {
+               if ( typeof opt.duration !== "number" ) {
+                       if ( opt.duration in jQuery.fx.speeds ) {
+                               opt.duration = jQuery.fx.speeds[ opt.duration ];
+
+                       } else {
+                               opt.duration = jQuery.fx.speeds._default;
+                       }
+               }
+       }
+
+       // Normalize opt.queue - true/undefined/null -> "fx"
+       if ( opt.queue == null || opt.queue === true ) {
+               opt.queue = "fx";
+       }
+
+       // Queueing
+       opt.old = opt.complete;
+
+       opt.complete = function() {
+               if ( isFunction( opt.old ) ) {
+                       opt.old.call( this );
+               }
+
+               if ( opt.queue ) {
+                       jQuery.dequeue( this, opt.queue );
+               }
+       };
+
+       return opt;
+};
+
+jQuery.fn.extend( {
+       fadeTo: function( speed, to, easing, callback ) {
+
+               // Show any hidden elements after setting opacity to 0
+               return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
+
+                       // Animate to the value specified
+                       .end().animate( { opacity: to }, speed, easing, callback );
+       },
+       animate: function( prop, speed, easing, callback ) {
+               var empty = jQuery.isEmptyObject( prop ),
+                       optall = jQuery.speed( speed, easing, callback ),
+                       doAnimation = function() {
+
+                               // Operate on a copy of prop so per-property easing won't be lost
+                               var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+                               // Empty animations, or finishing resolves immediately
+                               if ( empty || dataPriv.get( this, "finish" ) ) {
+                                       anim.stop( true );
+                               }
+                       };
+                       doAnimation.finish = doAnimation;
+
+               return empty || optall.queue === false ?
+                       this.each( doAnimation ) :
+                       this.queue( optall.queue, doAnimation );
+       },
+       stop: function( type, clearQueue, gotoEnd ) {
+               var stopQueue = function( hooks ) {
+                       var stop = hooks.stop;
+                       delete hooks.stop;
+                       stop( gotoEnd );
+               };
+
+               if ( typeof type !== "string" ) {
+                       gotoEnd = clearQueue;
+                       clearQueue = type;
+                       type = undefined;
+               }
+               if ( clearQueue ) {
+                       this.queue( type || "fx", [] );
+               }
+
+               return this.each( function() {
+                       var dequeue = true,
+                               index = type != null && type + "queueHooks",
+                               timers = jQuery.timers,
+                               data = dataPriv.get( this );
+
+                       if ( index ) {
+                               if ( data[ index ] && data[ index ].stop ) {
+                                       stopQueue( data[ index ] );
+                               }
+                       } else {
+                               for ( index in data ) {
+                                       if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+                                               stopQueue( data[ index ] );
+                                       }
+                               }
+                       }
+
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this &&
+                                       ( type == null || timers[ index ].queue === type ) ) {
+
+                                       timers[ index ].anim.stop( gotoEnd );
+                                       dequeue = false;
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // Start the next in the queue if the last step wasn't forced.
+                       // Timers currently will call their complete callbacks, which
+                       // will dequeue but only if they were gotoEnd.
+                       if ( dequeue || !gotoEnd ) {
+                               jQuery.dequeue( this, type );
+                       }
+               } );
+       },
+       finish: function( type ) {
+               if ( type !== false ) {
+                       type = type || "fx";
+               }
+               return this.each( function() {
+                       var index,
+                               data = dataPriv.get( this ),
+                               queue = data[ type + "queue" ],
+                               hooks = data[ type + "queueHooks" ],
+                               timers = jQuery.timers,
+                               length = queue ? queue.length : 0;
+
+                       // Enable finishing flag on private data
+                       data.finish = true;
+
+                       // Empty the queue first
+                       jQuery.queue( this, type, [] );
+
+                       if ( hooks && hooks.stop ) {
+                               hooks.stop.call( this, true );
+                       }
+
+                       // Look for any active animations, and finish them
+                       for ( index = timers.length; index--; ) {
+                               if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+                                       timers[ index ].anim.stop( true );
+                                       timers.splice( index, 1 );
+                               }
+                       }
+
+                       // Look for any animations in the old queue and finish them
+                       for ( index = 0; index < length; index++ ) {
+                               if ( queue[ index ] && queue[ index ].finish ) {
+                                       queue[ index ].finish.call( this );
+                               }
+                       }
+
+                       // Turn off finishing flag
+                       delete data.finish;
+               } );
+       }
+} );
+
+jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
+       var cssFn = jQuery.fn[ name ];
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return speed == null || typeof speed === "boolean" ?
+                       cssFn.apply( this, arguments ) :
+                       this.animate( genFx( name, true ), speed, easing, callback );
+       };
+} );
+
+// Generate shortcuts for custom animations
+jQuery.each( {
+       slideDown: genFx( "show" ),
+       slideUp: genFx( "hide" ),
+       slideToggle: genFx( "toggle" ),
+       fadeIn: { opacity: "show" },
+       fadeOut: { opacity: "hide" },
+       fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return this.animate( props, speed, easing, callback );
+       };
+} );
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+       var timer,
+               i = 0,
+               timers = jQuery.timers;
+
+       fxNow = Date.now();
+
+       for ( ; i < timers.length; i++ ) {
+               timer = timers[ i ];
+
+               // Run the timer and safely remove it when done (allowing for external removal)
+               if ( !timer() && timers[ i ] === timer ) {
+                       timers.splice( i--, 1 );
+               }
+       }
+
+       if ( !timers.length ) {
+               jQuery.fx.stop();
+       }
+       fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+       jQuery.timers.push( timer );
+       jQuery.fx.start();
+};
+
+jQuery.fx.interval = 13;
+jQuery.fx.start = function() {
+       if ( inProgress ) {
+               return;
+       }
+
+       inProgress = true;
+       schedule();
+};
+
+jQuery.fx.stop = function() {
+       inProgress = null;
+};
+
+jQuery.fx.speeds = {
+       slow: 600,
+       fast: 200,
+
+       // Default speed
+       _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+       time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+       type = type || "fx";
+
+       return this.queue( type, function( next, hooks ) {
+               var timeout = window.setTimeout( next, time );
+               hooks.stop = function() {
+                       window.clearTimeout( timeout );
+               };
+       } );
+};
+
+
+( function() {
+       var input = document.createElement( "input" ),
+               select = document.createElement( "select" ),
+               opt = select.appendChild( document.createElement( "option" ) );
+
+       input.type = "checkbox";
+
+       // Support: Android <=4.3 only
+       // Default value for a checkbox should be "on"
+       support.checkOn = input.value !== "";
+
+       // Support: IE <=11 only
+       // Must access selectedIndex to make default options select
+       support.optSelected = opt.selected;
+
+       // Support: IE <=11 only
+       // An input loses its value after becoming a radio
+       input = document.createElement( "input" );
+       input.value = "t";
+       input.type = "radio";
+       support.radioValue = input.value === "t";
+} )();
+
+
+var boolHook,
+       attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend( {
+       attr: function( name, value ) {
+               return access( this, jQuery.attr, name, value, arguments.length > 1 );
+       },
+
+       removeAttr: function( name ) {
+               return this.each( function() {
+                       jQuery.removeAttr( this, name );
+               } );
+       }
+} );
+
+jQuery.extend( {
+       attr: function( elem, name, value ) {
+               var ret, hooks,
+                       nType = elem.nodeType;
+
+               // Don't get/set attributes on text, comment and attribute nodes
+               if ( nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               // Fallback to prop when attributes are not supported
+               if ( typeof elem.getAttribute === "undefined" ) {
+                       return jQuery.prop( elem, name, value );
+               }
+
+               // Attribute hooks are determined by the lowercase version
+               // Grab necessary hook if one is defined
+               if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+                       hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
+                               ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
+               }
+
+               if ( value !== undefined ) {
+                       if ( value === null ) {
+                               jQuery.removeAttr( elem, name );
+                               return;
+                       }
+
+                       if ( hooks && "set" in hooks &&
+                               ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+                               return ret;
+                       }
+
+                       elem.setAttribute( name, value + "" );
+                       return value;
+               }
+
+               if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+                       return ret;
+               }
+
+               ret = jQuery.find.attr( elem, name );
+
+               // Non-existent attributes return null, we normalize to undefined
+               return ret == null ? undefined : ret;
+       },
+
+       attrHooks: {
+               type: {
+                       set: function( elem, value ) {
+                               if ( !support.radioValue && value === "radio" &&
+                                       nodeName( elem, "input" ) ) {
+                                       var val = elem.value;
+                                       elem.setAttribute( "type", value );
+                                       if ( val ) {
+                                               elem.value = val;
+                                       }
+                                       return value;
+                               }
+                       }
+               }
+       },
+
+       removeAttr: function( elem, value ) {
+               var name,
+                       i = 0,
+
+                       // Attribute names can contain non-HTML whitespace characters
+                       // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
+                       attrNames = value && value.match( rnothtmlwhite );
+
+               if ( attrNames && elem.nodeType === 1 ) {
+                       while ( ( name = attrNames[ i++ ] ) ) {
+                               elem.removeAttribute( name );
+                       }
+               }
+       }
+} );
+
+// Hooks for boolean attributes
+boolHook = {
+       set: function( elem, value, name ) {
+               if ( value === false ) {
+
+                       // Remove boolean attributes when set to false
+                       jQuery.removeAttr( elem, name );
+               } else {
+                       elem.setAttribute( name, name );
+               }
+               return name;
+       }
+};
+
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
+       var getter = attrHandle[ name ] || jQuery.find.attr;
+
+       attrHandle[ name ] = function( elem, name, isXML ) {
+               var ret, handle,
+                       lowercaseName = name.toLowerCase();
+
+               if ( !isXML ) {
+
+                       // Avoid an infinite loop by temporarily removing this function from the getter
+                       handle = attrHandle[ lowercaseName ];
+                       attrHandle[ lowercaseName ] = ret;
+                       ret = getter( elem, name, isXML ) != null ?
+                               lowercaseName :
+                               null;
+                       attrHandle[ lowercaseName ] = handle;
+               }
+               return ret;
+       };
+} );
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i,
+       rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend( {
+       prop: function( name, value ) {
+               return access( this, jQuery.prop, name, value, arguments.length > 1 );
+       },
+
+       removeProp: function( name ) {
+               return this.each( function() {
+                       delete this[ jQuery.propFix[ name ] || name ];
+               } );
+       }
+} );
+
+jQuery.extend( {
+       prop: function( elem, name, value ) {
+               var ret, hooks,
+                       nType = elem.nodeType;
+
+               // Don't get/set properties on text, comment and attribute nodes
+               if ( nType === 3 || nType === 8 || nType === 2 ) {
+                       return;
+               }
+
+               if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+
+                       // Fix name and attach hooks
+                       name = jQuery.propFix[ name ] || name;
+                       hooks = jQuery.propHooks[ name ];
+               }
+
+               if ( value !== undefined ) {
+                       if ( hooks && "set" in hooks &&
+                               ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+                               return ret;
+                       }
+
+                       return ( elem[ name ] = value );
+               }
+
+               if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+                       return ret;
+               }
+
+               return elem[ name ];
+       },
+
+       propHooks: {
+               tabIndex: {
+                       get: function( elem ) {
+
+                               // Support: IE <=9 - 11 only
+                               // elem.tabIndex doesn't always return the
+                               // correct value when it hasn't been explicitly set
+                               // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+                               // Use proper attribute retrieval(#12072)
+                               var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+                               if ( tabindex ) {
+                                       return parseInt( tabindex, 10 );
+                               }
+
+                               if (
+                                       rfocusable.test( elem.nodeName ) ||
+                                       rclickable.test( elem.nodeName ) &&
+                                       elem.href
+                               ) {
+                                       return 0;
+                               }
+
+                               return -1;
+                       }
+               }
+       },
+
+       propFix: {
+               "for": "htmlFor",
+               "class": "className"
+       }
+} );
+
+// Support: IE <=11 only
+// Accessing the selectedIndex property
+// forces the browser to respect setting selected
+// on the option
+// The getter ensures a default option is selected
+// when in an optgroup
+// eslint rule "no-unused-expressions" is disabled for this code
+// since it considers such accessions noop
+if ( !support.optSelected ) {
+       jQuery.propHooks.selected = {
+               get: function( elem ) {
+
+                       /* eslint no-unused-expressions: "off" */
+
+                       var parent = elem.parentNode;
+                       if ( parent && parent.parentNode ) {
+                               parent.parentNode.selectedIndex;
+                       }
+                       return null;
+               },
+               set: function( elem ) {
+
+                       /* eslint no-unused-expressions: "off" */
+
+                       var parent = elem.parentNode;
+                       if ( parent ) {
+                               parent.selectedIndex;
+
+                               if ( parent.parentNode ) {
+                                       parent.parentNode.selectedIndex;
+                               }
+                       }
+               }
+       };
+}
+
+jQuery.each( [
+       "tabIndex",
+       "readOnly",
+       "maxLength",
+       "cellSpacing",
+       "cellPadding",
+       "rowSpan",
+       "colSpan",
+       "useMap",
+       "frameBorder",
+       "contentEditable"
+], function() {
+       jQuery.propFix[ this.toLowerCase() ] = this;
+} );
+
+
+
+
+       // Strip and collapse whitespace according to HTML spec
+       // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+       function stripAndCollapse( value ) {
+               var tokens = value.match( rnothtmlwhite ) || [];
+               return tokens.join( " " );
+       }
+
+
+function getClass( elem ) {
+       return elem.getAttribute && elem.getAttribute( "class" ) || "";
+}
+
+function classesToArray( value ) {
+       if ( Array.isArray( value ) ) {
+               return value;
+       }
+       if ( typeof value === "string" ) {
+               return value.match( rnothtmlwhite ) || [];
+       }
+       return [];
+}
+
+jQuery.fn.extend( {
+       addClass: function( value ) {
+               var classes, elem, cur, curValue, clazz, j, finalValue,
+                       i = 0;
+
+               if ( isFunction( value ) ) {
+                       return this.each( function( j ) {
+                               jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+                       } );
+               }
+
+               classes = classesToArray( value );
+
+               if ( classes.length ) {
+                       while ( ( elem = this[ i++ ] ) ) {
+                               curValue = getClass( elem );
+                               cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( ( clazz = classes[ j++ ] ) ) {
+                                               if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+                                                       cur += clazz + " ";
+                                               }
+                                       }
+
+                                       // Only assign if different to avoid unneeded rendering.
+                                       finalValue = stripAndCollapse( cur );
+                                       if ( curValue !== finalValue ) {
+                                               elem.setAttribute( "class", finalValue );
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       removeClass: function( value ) {
+               var classes, elem, cur, curValue, clazz, j, finalValue,
+                       i = 0;
+
+               if ( isFunction( value ) ) {
+                       return this.each( function( j ) {
+                               jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+                       } );
+               }
+
+               if ( !arguments.length ) {
+                       return this.attr( "class", "" );
+               }
+
+               classes = classesToArray( value );
+
+               if ( classes.length ) {
+                       while ( ( elem = this[ i++ ] ) ) {
+                               curValue = getClass( elem );
+
+                               // This expression is here for better compressibility (see addClass)
+                               cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+                               if ( cur ) {
+                                       j = 0;
+                                       while ( ( clazz = classes[ j++ ] ) ) {
+
+                                               // Remove *all* instances
+                                               while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
+                                                       cur = cur.replace( " " + clazz + " ", " " );
+                                               }
+                                       }
+
+                                       // Only assign if different to avoid unneeded rendering.
+                                       finalValue = stripAndCollapse( cur );
+                                       if ( curValue !== finalValue ) {
+                                               elem.setAttribute( "class", finalValue );
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       toggleClass: function( value, stateVal ) {
+               var type = typeof value,
+                       isValidValue = type === "string" || Array.isArray( value );
+
+               if ( typeof stateVal === "boolean" && isValidValue ) {
+                       return stateVal ? this.addClass( value ) : this.removeClass( value );
+               }
+
+               if ( isFunction( value ) ) {
+                       return this.each( function( i ) {
+                               jQuery( this ).toggleClass(
+                                       value.call( this, i, getClass( this ), stateVal ),
+                                       stateVal
+                               );
+                       } );
+               }
+
+               return this.each( function() {
+                       var className, i, self, classNames;
+
+                       if ( isValidValue ) {
+
+                               // Toggle individual class names
+                               i = 0;
+                               self = jQuery( this );
+                               classNames = classesToArray( value );
+
+                               while ( ( className = classNames[ i++ ] ) ) {
+
+                                       // Check each className given, space separated list
+                                       if ( self.hasClass( className ) ) {
+                                               self.removeClass( className );
+                                       } else {
+                                               self.addClass( className );
+                                       }
+                               }
+
+                       // Toggle whole class name
+                       } else if ( value === undefined || type === "boolean" ) {
+                               className = getClass( this );
+                               if ( className ) {
+
+                                       // Store className if set
+                                       dataPriv.set( this, "__className__", className );
+                               }
+
+                               // If the element has a class name or if we're passed `false`,
+                               // then remove the whole classname (if there was one, the above saved it).
+                               // Otherwise bring back whatever was previously saved (if anything),
+                               // falling back to the empty string if nothing was stored.
+                               if ( this.setAttribute ) {
+                                       this.setAttribute( "class",
+                                               className || value === false ?
+                                               "" :
+                                               dataPriv.get( this, "__className__" ) || ""
+                                       );
+                               }
+                       }
+               } );
+       },
+
+       hasClass: function( selector ) {
+               var className, elem,
+                       i = 0;
+
+               className = " " + selector + " ";
+               while ( ( elem = this[ i++ ] ) ) {
+                       if ( elem.nodeType === 1 &&
+                               ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
+                                       return true;
+                       }
+               }
+
+               return false;
+       }
+} );
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend( {
+       val: function( value ) {
+               var hooks, ret, valueIsFunction,
+                       elem = this[ 0 ];
+
+               if ( !arguments.length ) {
+                       if ( elem ) {
+                               hooks = jQuery.valHooks[ elem.type ] ||
+                                       jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+                               if ( hooks &&
+                                       "get" in hooks &&
+                                       ( ret = hooks.get( elem, "value" ) ) !== undefined
+                               ) {
+                                       return ret;
+                               }
+
+                               ret = elem.value;
+
+                               // Handle most common string cases
+                               if ( typeof ret === "string" ) {
+                                       return ret.replace( rreturn, "" );
+                               }
+
+                               // Handle cases where value is null/undef or number
+                               return ret == null ? "" : ret;
+                       }
+
+                       return;
+               }
+
+               valueIsFunction = isFunction( value );
+
+               return this.each( function( i ) {
+                       var val;
+
+                       if ( this.nodeType !== 1 ) {
+                               return;
+                       }
+
+                       if ( valueIsFunction ) {
+                               val = value.call( this, i, jQuery( this ).val() );
+                       } else {
+                               val = value;
+                       }
+
+                       // Treat null/undefined as ""; convert numbers to string
+                       if ( val == null ) {
+                               val = "";
+
+                       } else if ( typeof val === "number" ) {
+                               val += "";
+
+                       } else if ( Array.isArray( val ) ) {
+                               val = jQuery.map( val, function( value ) {
+                                       return value == null ? "" : value + "";
+                               } );
+                       }
+
+                       hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
+                               this.value = val;
+                       }
+               } );
+       }
+} );
+
+jQuery.extend( {
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+
+                               var val = jQuery.find.attr( elem, "value" );
+                               return val != null ?
+                                       val :
+
+                                       // Support: IE <=10 - 11 only
+                                       // option.text throws exceptions (#14686, #14858)
+                                       // Strip and collapse whitespace
+                                       // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+                                       stripAndCollapse( jQuery.text( elem ) );
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var value, option, i,
+                                       options = elem.options,
+                                       index = elem.selectedIndex,
+                                       one = elem.type === "select-one",
+                                       values = one ? null : [],
+                                       max = one ? index + 1 : options.length;
+
+                               if ( index < 0 ) {
+                                       i = max;
+
+                               } else {
+                                       i = one ? index : 0;
+                               }
+
+                               // Loop through all the selected options
+                               for ( ; i < max; i++ ) {
+                                       option = options[ i ];
+
+                                       // Support: IE <=9 only
+                                       // IE8-9 doesn't update selected after form reset (#2551)
+                                       if ( ( option.selected || i === index ) &&
+
+                                                       // Don't return options that are disabled or in a disabled optgroup
+                                                       !option.disabled &&
+                                                       ( !option.parentNode.disabled ||
+                                                               !nodeName( option.parentNode, "optgroup" ) ) ) {
+
+                                               // Get the specific value for the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
+
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var optionSet, option,
+                                       options = elem.options,
+                                       values = jQuery.makeArray( value ),
+                                       i = options.length;
+
+                               while ( i-- ) {
+                                       option = options[ i ];
+
+                                       /* eslint-disable no-cond-assign */
+
+                                       if ( option.selected =
+                                               jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
+                                       ) {
+                                               optionSet = true;
+                                       }
+
+                                       /* eslint-enable no-cond-assign */
+                               }
+
+                               // Force browsers to behave consistently when non-matching value is set
+                               if ( !optionSet ) {
+                                       elem.selectedIndex = -1;
+                               }
+                               return values;
+                       }
+               }
+       }
+} );
+
+// Radios and checkboxes getter/setter
+jQuery.each( [ "radio", "checkbox" ], function() {
+       jQuery.valHooks[ this ] = {
+               set: function( elem, value ) {
+                       if ( Array.isArray( value ) ) {
+                               return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
+                       }
+               }
+       };
+       if ( !support.checkOn ) {
+               jQuery.valHooks[ this ].get = function( elem ) {
+                       return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+               };
+       }
+} );
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+support.focusin = "onfocusin" in window;
+
+
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+       stopPropagationCallback = function( e ) {
+               e.stopPropagation();
+       };
+
+jQuery.extend( jQuery.event, {
+
+       trigger: function( event, data, elem, onlyHandlers ) {
+
+               var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
+                       eventPath = [ elem || document ],
+                       type = hasOwn.call( event, "type" ) ? event.type : event,
+                       namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+               cur = lastElement = tmp = elem = elem || document;
+
+               // Don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               // focus/blur morphs to focusin/out; ensure we're not firing them right now
+               if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+                       return;
+               }
+
+               if ( type.indexOf( "." ) > -1 ) {
+
+                       // Namespaced trigger; create a regexp to match event type in handle()
+                       namespaces = type.split( "." );
+                       type = namespaces.shift();
+                       namespaces.sort();
+               }
+               ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+               // Caller can pass in a jQuery.Event object, Object, or just an event type string
+               event = event[ jQuery.expando ] ?
+                       event :
+                       new jQuery.Event( type, typeof event === "object" && event );
+
+               // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+               event.isTrigger = onlyHandlers ? 2 : 3;
+               event.namespace = namespaces.join( "." );
+               event.rnamespace = event.namespace ?
+                       new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+                       null;
+
+               // Clean up the event in case it is being reused
+               event.result = undefined;
+               if ( !event.target ) {
+                       event.target = elem;
+               }
+
+               // Clone any incoming data and prepend the event, creating the handler arg list
+               data = data == null ?
+                       [ event ] :
+                       jQuery.makeArray( data, [ event ] );
+
+               // Allow special events to draw outside the lines
+               special = jQuery.event.special[ type ] || {};
+               if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+                       return;
+               }
+
+               // Determine event propagation path in advance, per W3C events spec (#9951)
+               // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+               if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
+
+                       bubbleType = special.delegateType || type;
+                       if ( !rfocusMorph.test( bubbleType + type ) ) {
+                               cur = cur.parentNode;
+                       }
+                       for ( ; cur; cur = cur.parentNode ) {
+                               eventPath.push( cur );
+                               tmp = cur;
+                       }
+
+                       // Only add window if we got to document (e.g., not plain obj or detached DOM)
+                       if ( tmp === ( elem.ownerDocument || document ) ) {
+                               eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+                       }
+               }
+
+               // Fire handlers on the event path
+               i = 0;
+               while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+                       lastElement = cur;
+                       event.type = i > 1 ?
+                               bubbleType :
+                               special.bindType || type;
+
+                       // jQuery handler
+                       handle = (
+                                       dataPriv.get( cur, "events" ) || Object.create( null )
+                               )[ event.type ] &&
+                               dataPriv.get( cur, "handle" );
+                       if ( handle ) {
+                               handle.apply( cur, data );
+                       }
+
+                       // Native handler
+                       handle = ontype && cur[ ontype ];
+                       if ( handle && handle.apply && acceptData( cur ) ) {
+                               event.result = handle.apply( cur, data );
+                               if ( event.result === false ) {
+                                       event.preventDefault();
+                               }
+                       }
+               }
+               event.type = type;
+
+               // If nobody prevented the default action, do it now
+               if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+                       if ( ( !special._default ||
+                               special._default.apply( eventPath.pop(), data ) === false ) &&
+                               acceptData( elem ) ) {
+
+                               // Call a native DOM method on the target with the same name as the event.
+                               // Don't do default actions on window, that's where global variables be (#6170)
+                               if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
+
+                                       // Don't re-trigger an onFOO event when we call its FOO() method
+                                       tmp = elem[ ontype ];
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = null;
+                                       }
+
+                                       // Prevent re-triggering of the same event, since we already bubbled it above
+                                       jQuery.event.triggered = type;
+
+                                       if ( event.isPropagationStopped() ) {
+                                               lastElement.addEventListener( type, stopPropagationCallback );
+                                       }
+
+                                       elem[ type ]();
+
+                                       if ( event.isPropagationStopped() ) {
+                                               lastElement.removeEventListener( type, stopPropagationCallback );
+                                       }
+
+                                       jQuery.event.triggered = undefined;
+
+                                       if ( tmp ) {
+                                               elem[ ontype ] = tmp;
+                                       }
+                               }
+                       }
+               }
+
+               return event.result;
+       },
+
+       // Piggyback on a donor event to simulate a different one
+       // Used only for `focus(in | out)` events
+       simulate: function( type, elem, event ) {
+               var e = jQuery.extend(
+                       new jQuery.Event(),
+                       event,
+                       {
+                               type: type,
+                               isSimulated: true
+                       }
+               );
+
+               jQuery.event.trigger( e, null, elem );
+       }
+
+} );
+
+jQuery.fn.extend( {
+
+       trigger: function( type, data ) {
+               return this.each( function() {
+                       jQuery.event.trigger( type, data, this );
+               } );
+       },
+       triggerHandler: function( type, data ) {
+               var elem = this[ 0 ];
+               if ( elem ) {
+                       return jQuery.event.trigger( type, data, elem, true );
+               }
+       }
+} );
+
+
+// Support: Firefox <=44
+// Firefox doesn't have focus(in | out) events
+// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+//
+// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+// focus(in | out) events fire after focus & blur events,
+// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+if ( !support.focusin ) {
+       jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+               // Attach a single capturing handler on the document while someone wants focusin/focusout
+               var handler = function( event ) {
+                       jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+               };
+
+               jQuery.event.special[ fix ] = {
+                       setup: function() {
+
+                               // Handle: regular nodes (via `this.ownerDocument`), window
+                               // (via `this.document`) & document (via `this`).
+                               var doc = this.ownerDocument || this.document || this,
+                                       attaches = dataPriv.access( doc, fix );
+
+                               if ( !attaches ) {
+                                       doc.addEventListener( orig, handler, true );
+                               }
+                               dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+                       },
+                       teardown: function() {
+                               var doc = this.ownerDocument || this.document || this,
+                                       attaches = dataPriv.access( doc, fix ) - 1;
+
+                               if ( !attaches ) {
+                                       doc.removeEventListener( orig, handler, true );
+                                       dataPriv.remove( doc, fix );
+
+                               } else {
+                                       dataPriv.access( doc, fix, attaches );
+                               }
+                       }
+               };
+       } );
+}
+var location = window.location;
+
+var nonce = { guid: Date.now() };
+
+var rquery = ( /\?/ );
+
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+       var xml;
+       if ( !data || typeof data !== "string" ) {
+               return null;
+       }
+
+       // Support: IE 9 - 11 only
+       // IE throws on parseFromString with invalid input.
+       try {
+               xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+       } catch ( e ) {
+               xml = undefined;
+       }
+
+       if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+               jQuery.error( "Invalid XML: " + data );
+       }
+       return xml;
+};
+
+
+var
+       rbracket = /\[\]$/,
+       rCRLF = /\r?\n/g,
+       rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+       rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+       var name;
+
+       if ( Array.isArray( obj ) ) {
+
+               // Serialize array item.
+               jQuery.each( obj, function( i, v ) {
+                       if ( traditional || rbracket.test( prefix ) ) {
+
+                               // Treat each array item as a scalar.
+                               add( prefix, v );
+
+                       } else {
+
+                               // Item is non-scalar (array or object), encode its numeric index.
+                               buildParams(
+                                       prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
+                                       v,
+                                       traditional,
+                                       add
+                               );
+                       }
+               } );
+
+       } else if ( !traditional && toType( obj ) === "object" ) {
+
+               // Serialize object item.
+               for ( name in obj ) {
+                       buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+               }
+
+       } else {
+
+               // Serialize scalar item.
+               add( prefix, obj );
+       }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+       var prefix,
+               s = [],
+               add = function( key, valueOrFunction ) {
+
+                       // If value is a function, invoke it and use its return value
+                       var value = isFunction( valueOrFunction ) ?
+                               valueOrFunction() :
+                               valueOrFunction;
+
+                       s[ s.length ] = encodeURIComponent( key ) + "=" +
+                               encodeURIComponent( value == null ? "" : value );
+               };
+
+       if ( a == null ) {
+               return "";
+       }
+
+       // If an array was passed in, assume that it is an array of form elements.
+       if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+
+               // Serialize the form elements
+               jQuery.each( a, function() {
+                       add( this.name, this.value );
+               } );
+
+       } else {
+
+               // If traditional, encode the "old" way (the way 1.3.2 or older
+               // did it), otherwise encode params recursively.
+               for ( prefix in a ) {
+                       buildParams( prefix, a[ prefix ], traditional, add );
+               }
+       }
+
+       // Return the resulting serialization
+       return s.join( "&" );
+};
+
+jQuery.fn.extend( {
+       serialize: function() {
+               return jQuery.param( this.serializeArray() );
+       },
+       serializeArray: function() {
+               return this.map( function() {
+
+                       // Can add propHook for "elements" to filter or add form elements
+                       var elements = jQuery.prop( this, "elements" );
+                       return elements ? jQuery.makeArray( elements ) : this;
+               } )
+               .filter( function() {
+                       var type = this.type;
+
+                       // Use .is( ":disabled" ) so that fieldset[disabled] works
+                       return this.name && !jQuery( this ).is( ":disabled" ) &&
+                               rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+                               ( this.checked || !rcheckableType.test( type ) );
+               } )
+               .map( function( _i, elem ) {
+                       var val = jQuery( this ).val();
+
+                       if ( val == null ) {
+                               return null;
+                       }
+
+                       if ( Array.isArray( val ) ) {
+                               return jQuery.map( val, function( val ) {
+                                       return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                               } );
+                       }
+
+                       return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+               } ).get();
+       }
+} );
+
+
+var
+       r20 = /%20/g,
+       rhash = /#.*$/,
+       rantiCache = /([?&])_=[^&]*/,
+       rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+
+       // #7653, #8125, #8152: local protocol detection
+       rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+       rnoContent = /^(?:GET|HEAD)$/,
+       rprotocol = /^\/\//,
+
+       /* Prefilters
+        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+        * 2) These are called:
+        *    - BEFORE asking for a transport
+        *    - AFTER param serialization (s.data is a string if s.processData is true)
+        * 3) key is the dataType
+        * 4) the catchall symbol "*" can be used
+        * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+        */
+       prefilters = {},
+
+       /* Transports bindings
+        * 1) key is the dataType
+        * 2) the catchall symbol "*" can be used
+        * 3) selection will start with transport dataType and THEN go to "*" if needed
+        */
+       transports = {},
+
+       // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+       allTypes = "*/".concat( "*" ),
+
+       // Anchor tag for parsing the document origin
+       originAnchor = document.createElement( "a" );
+       originAnchor.href = location.href;
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+       // dataTypeExpression is optional and defaults to "*"
+       return function( dataTypeExpression, func ) {
+
+               if ( typeof dataTypeExpression !== "string" ) {
+                       func = dataTypeExpression;
+                       dataTypeExpression = "*";
+               }
+
+               var dataType,
+                       i = 0,
+                       dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
+
+               if ( isFunction( func ) ) {
+
+                       // For each dataType in the dataTypeExpression
+                       while ( ( dataType = dataTypes[ i++ ] ) ) {
+
+                               // Prepend if requested
+                               if ( dataType[ 0 ] === "+" ) {
+                                       dataType = dataType.slice( 1 ) || "*";
+                                       ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
+
+                               // Otherwise append
+                               } else {
+                                       ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
+                               }
+                       }
+               }
+       };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+       var inspected = {},
+               seekingTransport = ( structure === transports );
+
+       function inspect( dataType ) {
+               var selected;
+               inspected[ dataType ] = true;
+               jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+                       var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+                       if ( typeof dataTypeOrTransport === "string" &&
+                               !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+
+                               options.dataTypes.unshift( dataTypeOrTransport );
+                               inspect( dataTypeOrTransport );
+                               return false;
+                       } else if ( seekingTransport ) {
+                               return !( selected = dataTypeOrTransport );
+                       }
+               } );
+               return selected;
+       }
+
+       return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+       var key, deep,
+               flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+       for ( key in src ) {
+               if ( src[ key ] !== undefined ) {
+                       ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+               }
+       }
+       if ( deep ) {
+               jQuery.extend( true, target, deep );
+       }
+
+       return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+       var ct, type, finalDataType, firstDataType,
+               contents = s.contents,
+               dataTypes = s.dataTypes;
+
+       // Remove auto dataType and get content-type in the process
+       while ( dataTypes[ 0 ] === "*" ) {
+               dataTypes.shift();
+               if ( ct === undefined ) {
+                       ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
+               }
+       }
+
+       // Check if we're dealing with a known content-type
+       if ( ct ) {
+               for ( type in contents ) {
+                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                               dataTypes.unshift( type );
+                               break;
+                       }
+               }
+       }
+
+       // Check to see if we have a response for the expected dataType
+       if ( dataTypes[ 0 ] in responses ) {
+               finalDataType = dataTypes[ 0 ];
+       } else {
+
+               // Try convertible dataTypes
+               for ( type in responses ) {
+                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
+                               finalDataType = type;
+                               break;
+                       }
+                       if ( !firstDataType ) {
+                               firstDataType = type;
+                       }
+               }
+
+               // Or just use first one
+               finalDataType = finalDataType || firstDataType;
+       }
+
+       // If we found a dataType
+       // We add the dataType to the list if needed
+       // and return the corresponding response
+       if ( finalDataType ) {
+               if ( finalDataType !== dataTypes[ 0 ] ) {
+                       dataTypes.unshift( finalDataType );
+               }
+               return responses[ finalDataType ];
+       }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+       var conv2, current, conv, tmp, prev,
+               converters = {},
+
+               // Work with a copy of dataTypes in case we need to modify it for conversion
+               dataTypes = s.dataTypes.slice();
+
+       // Create converters map with lowercased keys
+       if ( dataTypes[ 1 ] ) {
+               for ( conv in s.converters ) {
+                       converters[ conv.toLowerCase() ] = s.converters[ conv ];
+               }
+       }
+
+       current = dataTypes.shift();
+
+       // Convert to each sequential dataType
+       while ( current ) {
+
+               if ( s.responseFields[ current ] ) {
+                       jqXHR[ s.responseFields[ current ] ] = response;
+               }
+
+               // Apply the dataFilter if provided
+               if ( !prev && isSuccess && s.dataFilter ) {
+                       response = s.dataFilter( response, s.dataType );
+               }
+
+               prev = current;
+               current = dataTypes.shift();
+
+               if ( current ) {
+
+                       // There's only work to do if current dataType is non-auto
+                       if ( current === "*" ) {
+
+                               current = prev;
+
+                       // Convert response if prev dataType is non-auto and differs from current
+                       } else if ( prev !== "*" && prev !== current ) {
+
+                               // Seek a direct converter
+                               conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+                               // If none found, seek a pair
+                               if ( !conv ) {
+                                       for ( conv2 in converters ) {
+
+                                               // If conv2 outputs current
+                                               tmp = conv2.split( " " );
+                                               if ( tmp[ 1 ] === current ) {
+
+                                                       // If prev can be converted to accepted input
+                                                       conv = converters[ prev + " " + tmp[ 0 ] ] ||
+                                                               converters[ "* " + tmp[ 0 ] ];
+                                                       if ( conv ) {
+
+                                                               // Condense equivalence converters
+                                                               if ( conv === true ) {
+                                                                       conv = converters[ conv2 ];
+
+                                                               // Otherwise, insert the intermediate dataType
+                                                               } else if ( converters[ conv2 ] !== true ) {
+                                                                       current = tmp[ 0 ];
+                                                                       dataTypes.unshift( tmp[ 1 ] );
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Apply converter (if not an equivalence)
+                               if ( conv !== true ) {
+
+                                       // Unless errors are allowed to bubble, catch and return them
+                                       if ( conv && s.throws ) {
+                                               response = conv( response );
+                                       } else {
+                                               try {
+                                                       response = conv( response );
+                                               } catch ( e ) {
+                                                       return {
+                                                               state: "parsererror",
+                                                               error: conv ? e : "No conversion from " + prev + " to " + current
+                                                       };
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return { state: "success", data: response };
+}
+
+jQuery.extend( {
+
+       // Counter for holding the number of active queries
+       active: 0,
+
+       // Last-Modified header cache for next request
+       lastModified: {},
+       etag: {},
+
+       ajaxSettings: {
+               url: location.href,
+               type: "GET",
+               isLocal: rlocalProtocol.test( location.protocol ),
+               global: true,
+               processData: true,
+               async: true,
+               contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+
+               /*
+               timeout: 0,
+               data: null,
+               dataType: null,
+               username: null,
+               password: null,
+               cache: null,
+               throws: false,
+               traditional: false,
+               headers: {},
+               */
+
+               accepts: {
+                       "*": allTypes,
+                       text: "text/plain",
+                       html: "text/html",
+                       xml: "application/xml, text/xml",
+                       json: "application/json, text/javascript"
+               },
+
+               contents: {
+                       xml: /\bxml\b/,
+                       html: /\bhtml/,
+                       json: /\bjson\b/
+               },
+
+               responseFields: {
+                       xml: "responseXML",
+                       text: "responseText",
+                       json: "responseJSON"
+               },
+
+               // Data converters
+               // Keys separate source (or catchall "*") and destination types with a single space
+               converters: {
+
+                       // Convert anything to text
+                       "* text": String,
+
+                       // Text to html (true = no transformation)
+                       "text html": true,
+
+                       // Evaluate text as a json expression
+                       "text json": JSON.parse,
+
+                       // Parse text as xml
+                       "text xml": jQuery.parseXML
+               },
+
+               // For options that shouldn't be deep extended:
+               // you can add your own custom options here if
+               // and when you create one that shouldn't be
+               // deep extended (see ajaxExtend)
+               flatOptions: {
+                       url: true,
+                       context: true
+               }
+       },
+
+       // Creates a full fledged settings object into target
+       // with both ajaxSettings and settings fields.
+       // If target is omitted, writes into ajaxSettings.
+       ajaxSetup: function( target, settings ) {
+               return settings ?
+
+                       // Building a settings object
+                       ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+                       // Extending ajaxSettings
+                       ajaxExtend( jQuery.ajaxSettings, target );
+       },
+
+       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+       ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+       // Main method
+       ajax: function( url, options ) {
+
+               // If url is an object, simulate pre-1.5 signature
+               if ( typeof url === "object" ) {
+                       options = url;
+                       url = undefined;
+               }
+
+               // Force options to be an object
+               options = options || {};
+
+               var transport,
+
+                       // URL without anti-cache param
+                       cacheURL,
+
+                       // Response headers
+                       responseHeadersString,
+                       responseHeaders,
+
+                       // timeout handle
+                       timeoutTimer,
+
+                       // Url cleanup var
+                       urlAnchor,
+
+                       // Request state (becomes false upon send and true upon completion)
+                       completed,
+
+                       // To know if global events are to be dispatched
+                       fireGlobals,
+
+                       // Loop variable
+                       i,
+
+                       // uncached part of the url
+                       uncached,
+
+                       // Create the final options object
+                       s = jQuery.ajaxSetup( {}, options ),
+
+                       // Callbacks context
+                       callbackContext = s.context || s,
+
+                       // Context for global events is callbackContext if it is a DOM node or jQuery collection
+                       globalEventContext = s.context &&
+                               ( callbackContext.nodeType || callbackContext.jquery ) ?
+                                       jQuery( callbackContext ) :
+                                       jQuery.event,
+
+                       // Deferreds
+                       deferred = jQuery.Deferred(),
+                       completeDeferred = jQuery.Callbacks( "once memory" ),
+
+                       // Status-dependent callbacks
+                       statusCode = s.statusCode || {},
+
+                       // Headers (they are sent all at once)
+                       requestHeaders = {},
+                       requestHeadersNames = {},
+
+                       // Default abort message
+                       strAbort = "canceled",
+
+                       // Fake xhr
+                       jqXHR = {
+                               readyState: 0,
+
+                               // Builds headers hashtable if needed
+                               getResponseHeader: function( key ) {
+                                       var match;
+                                       if ( completed ) {
+                                               if ( !responseHeaders ) {
+                                                       responseHeaders = {};
+                                                       while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
+                                                               responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
+                                                                       ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
+                                                                               .concat( match[ 2 ] );
+                                                       }
+                                               }
+                                               match = responseHeaders[ key.toLowerCase() + " " ];
+                                       }
+                                       return match == null ? null : match.join( ", " );
+                               },
+
+                               // Raw string
+                               getAllResponseHeaders: function() {
+                                       return completed ? responseHeadersString : null;
+                               },
+
+                               // Caches the header
+                               setRequestHeader: function( name, value ) {
+                                       if ( completed == null ) {
+                                               name = requestHeadersNames[ name.toLowerCase() ] =
+                                                       requestHeadersNames[ name.toLowerCase() ] || name;
+                                               requestHeaders[ name ] = value;
+                                       }
+                                       return this;
+                               },
+
+                               // Overrides response content-type header
+                               overrideMimeType: function( type ) {
+                                       if ( completed == null ) {
+                                               s.mimeType = type;
+                                       }
+                                       return this;
+                               },
+
+                               // Status-dependent callbacks
+                               statusCode: function( map ) {
+                                       var code;
+                                       if ( map ) {
+                                               if ( completed ) {
+
+                                                       // Execute the appropriate callbacks
+                                                       jqXHR.always( map[ jqXHR.status ] );
+                                               } else {
+
+                                                       // Lazy-add the new callbacks in a way that preserves old ones
+                                                       for ( code in map ) {
+                                                               statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+                                                       }
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // Cancel the request
+                               abort: function( statusText ) {
+                                       var finalText = statusText || strAbort;
+                                       if ( transport ) {
+                                               transport.abort( finalText );
+                                       }
+                                       done( 0, finalText );
+                                       return this;
+                               }
+                       };
+
+               // Attach deferreds
+               deferred.promise( jqXHR );
+
+               // Add protocol if not provided (prefilters might expect it)
+               // Handle falsy url in the settings object (#10093: consistency with old signature)
+               // We also use the url parameter if available
+               s.url = ( ( url || s.url || location.href ) + "" )
+                       .replace( rprotocol, location.protocol + "//" );
+
+               // Alias method option to type as per ticket #12004
+               s.type = options.method || options.type || s.method || s.type;
+
+               // Extract dataTypes list
+               s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
+
+               // A cross-domain request is in order when the origin doesn't match the current origin.
+               if ( s.crossDomain == null ) {
+                       urlAnchor = document.createElement( "a" );
+
+                       // Support: IE <=8 - 11, Edge 12 - 15
+                       // IE throws exception on accessing the href property if url is malformed,
+                       // e.g. http://example.com:80x/
+                       try {
+                               urlAnchor.href = s.url;
+
+                               // Support: IE <=8 - 11 only
+                               // Anchor's host property isn't correctly set when s.url is relative
+                               urlAnchor.href = urlAnchor.href;
+                               s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+                                       urlAnchor.protocol + "//" + urlAnchor.host;
+                       } catch ( e ) {
+
+                               // If there is an error parsing the URL, assume it is crossDomain,
+                               // it can be rejected by the transport if it is invalid
+                               s.crossDomain = true;
+                       }
+               }
+
+               // Convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" ) {
+                       s.data = jQuery.param( s.data, s.traditional );
+               }
+
+               // Apply prefilters
+               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+               // If request was aborted inside a prefilter, stop there
+               if ( completed ) {
+                       return jqXHR;
+               }
+
+               // We can fire global events as of now if asked to
+               // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+               fireGlobals = jQuery.event && s.global;
+
+               // Watch for a new set of requests
+               if ( fireGlobals && jQuery.active++ === 0 ) {
+                       jQuery.event.trigger( "ajaxStart" );
+               }
+
+               // Uppercase the type
+               s.type = s.type.toUpperCase();
+
+               // Determine if request has content
+               s.hasContent = !rnoContent.test( s.type );
+
+               // Save the URL in case we're toying with the If-Modified-Since
+               // and/or If-None-Match header later on
+               // Remove hash to simplify url manipulation
+               cacheURL = s.url.replace( rhash, "" );
+
+               // More options handling for requests with no content
+               if ( !s.hasContent ) {
+
+                       // Remember the hash so we can put it back
+                       uncached = s.url.slice( cacheURL.length );
+
+                       // If data is available and should be processed, append data to url
+                       if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
+                               cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
+
+                               // #9682: remove data so that it's not used in an eventual retry
+                               delete s.data;
+                       }
+
+                       // Add or update anti-cache param if needed
+                       if ( s.cache === false ) {
+                               cacheURL = cacheURL.replace( rantiCache, "$1" );
+                               uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
+                                       uncached;
+                       }
+
+                       // Put hash and anti-cache on the URL that will be requested (gh-1732)
+                       s.url = cacheURL + uncached;
+
+               // Change '%20' to '+' if this is encoded form body content (gh-2658)
+               } else if ( s.data && s.processData &&
+                       ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
+                       s.data = s.data.replace( r20, "+" );
+               }
+
+               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+               if ( s.ifModified ) {
+                       if ( jQuery.lastModified[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+                       }
+                       if ( jQuery.etag[ cacheURL ] ) {
+                               jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+                       }
+               }
+
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                       jqXHR.setRequestHeader( "Content-Type", s.contentType );
+               }
+
+               // Set the Accepts header for the server, depending on the dataType
+               jqXHR.setRequestHeader(
+                       "Accept",
+                       s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+                               s.accepts[ s.dataTypes[ 0 ] ] +
+                                       ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+                               s.accepts[ "*" ]
+               );
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       jqXHR.setRequestHeader( i, s.headers[ i ] );
+               }
+
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend &&
+                       ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
+
+                       // Abort if not done already and return
+                       return jqXHR.abort();
+               }
+
+               // Aborting is no longer a cancellation
+               strAbort = "abort";
+
+               // Install callbacks on deferreds
+               completeDeferred.add( s.complete );
+               jqXHR.done( s.success );
+               jqXHR.fail( s.error );
+
+               // Get transport
+               transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+               // If no transport, we auto-abort
+               if ( !transport ) {
+                       done( -1, "No Transport" );
+               } else {
+                       jqXHR.readyState = 1;
+
+                       // Send global event
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                       }
+
+                       // If request was aborted inside ajaxSend, stop there
+                       if ( completed ) {
+                               return jqXHR;
+                       }
+
+                       // Timeout
+                       if ( s.async && s.timeout > 0 ) {
+                               timeoutTimer = window.setTimeout( function() {
+                                       jqXHR.abort( "timeout" );
+                               }, s.timeout );
+                       }
+
+                       try {
+                               completed = false;
+                               transport.send( requestHeaders, done );
+                       } catch ( e ) {
+
+                               // Rethrow post-completion exceptions
+                               if ( completed ) {
+                                       throw e;
+                               }
+
+                               // Propagate others as results
+                               done( -1, e );
+                       }
+               }
+
+               // Callback for when everything is done
+               function done( status, nativeStatusText, responses, headers ) {
+                       var isSuccess, success, error, response, modified,
+                               statusText = nativeStatusText;
+
+                       // Ignore repeat invocations
+                       if ( completed ) {
+                               return;
+                       }
+
+                       completed = true;
+
+                       // Clear timeout if it exists
+                       if ( timeoutTimer ) {
+                               window.clearTimeout( timeoutTimer );
+                       }
+
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jqXHR object will be used)
+                       transport = undefined;
+
+                       // Cache response headers
+                       responseHeadersString = headers || "";
+
+                       // Set readyState
+                       jqXHR.readyState = status > 0 ? 4 : 0;
+
+                       // Determine if successful
+                       isSuccess = status >= 200 && status < 300 || status === 304;
+
+                       // Get response data
+                       if ( responses ) {
+                               response = ajaxHandleResponses( s, jqXHR, responses );
+                       }
+
+                       // Use a noop converter for missing script
+                       if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) {
+                               s.converters[ "text script" ] = function() {};
+                       }
+
+                       // Convert no matter what (that way responseXXX fields are always set)
+                       response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+                       // If successful, handle type chaining
+                       if ( isSuccess ) {
+
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+                                       modified = jqXHR.getResponseHeader( "Last-Modified" );
+                                       if ( modified ) {
+                                               jQuery.lastModified[ cacheURL ] = modified;
+                                       }
+                                       modified = jqXHR.getResponseHeader( "etag" );
+                                       if ( modified ) {
+                                               jQuery.etag[ cacheURL ] = modified;
+                                       }
+                               }
+
+                               // if no content
+                               if ( status === 204 || s.type === "HEAD" ) {
+                                       statusText = "nocontent";
+
+                               // if not modified
+                               } else if ( status === 304 ) {
+                                       statusText = "notmodified";
+
+                               // If we have data, let's convert it
+                               } else {
+                                       statusText = response.state;
+                                       success = response.data;
+                                       error = response.error;
+                                       isSuccess = !error;
+                               }
+                       } else {
+
+                               // Extract error from statusText and normalize for non-aborts
+                               error = statusText;
+                               if ( status || !statusText ) {
+                                       statusText = "error";
+                                       if ( status < 0 ) {
+                                               status = 0;
+                                       }
+                               }
+                       }
+
+                       // Set data for the fake xhr object
+                       jqXHR.status = status;
+                       jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+                       // Success/Error
+                       if ( isSuccess ) {
+                               deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                       } else {
+                               deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                       }
+
+                       // Status-dependent callbacks
+                       jqXHR.statusCode( statusCode );
+                       statusCode = undefined;
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+                                       [ jqXHR, s, isSuccess ? success : error ] );
+                       }
+
+                       // Complete
+                       completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+
+                               // Handle the global AJAX counter
+                               if ( !( --jQuery.active ) ) {
+                                       jQuery.event.trigger( "ajaxStop" );
+                               }
+                       }
+               }
+
+               return jqXHR;
+       },
+
+       getJSON: function( url, data, callback ) {
+               return jQuery.get( url, data, callback, "json" );
+       },
+
+       getScript: function( url, callback ) {
+               return jQuery.get( url, undefined, callback, "script" );
+       }
+} );
+
+jQuery.each( [ "get", "post" ], function( _i, method ) {
+       jQuery[ method ] = function( url, data, callback, type ) {
+
+               // Shift arguments if data argument was omitted
+               if ( isFunction( data ) ) {
+                       type = type || callback;
+                       callback = data;
+                       data = undefined;
+               }
+
+               // The url can be an options object (which then must have .url)
+               return jQuery.ajax( jQuery.extend( {
+                       url: url,
+                       type: method,
+                       dataType: type,
+                       data: data,
+                       success: callback
+               }, jQuery.isPlainObject( url ) && url ) );
+       };
+} );
+
+jQuery.ajaxPrefilter( function( s ) {
+       var i;
+       for ( i in s.headers ) {
+               if ( i.toLowerCase() === "content-type" ) {
+                       s.contentType = s.headers[ i ] || "";
+               }
+       }
+} );
+
+
+jQuery._evalUrl = function( url, options, doc ) {
+       return jQuery.ajax( {
+               url: url,
+
+               // Make this explicit, since user can override this through ajaxSetup (#11264)
+               type: "GET",
+               dataType: "script",
+               cache: true,
+               async: false,
+               global: false,
+
+               // Only evaluate the response if it is successful (gh-4126)
+               // dataFilter is not invoked for failure responses, so using it instead
+               // of the default converter is kludgy but it works.
+               converters: {
+                       "text script": function() {}
+               },
+               dataFilter: function( response ) {
+                       jQuery.globalEval( response, options, doc );
+               }
+       } );
+};
+
+
+jQuery.fn.extend( {
+       wrapAll: function( html ) {
+               var wrap;
+
+               if ( this[ 0 ] ) {
+                       if ( isFunction( html ) ) {
+                               html = html.call( this[ 0 ] );
+                       }
+
+                       // The elements to wrap the target around
+                       wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+                       if ( this[ 0 ].parentNode ) {
+                               wrap.insertBefore( this[ 0 ] );
+                       }
+
+                       wrap.map( function() {
+                               var elem = this;
+
+                               while ( elem.firstElementChild ) {
+                                       elem = elem.firstElementChild;
+                               }
+
+                               return elem;
+                       } ).append( this );
+               }
+
+               return this;
+       },
+
+       wrapInner: function( html ) {
+               if ( isFunction( html ) ) {
+                       return this.each( function( i ) {
+                               jQuery( this ).wrapInner( html.call( this, i ) );
+                       } );
+               }
+
+               return this.each( function() {
+                       var self = jQuery( this ),
+                               contents = self.contents();
+
+                       if ( contents.length ) {
+                               contents.wrapAll( html );
+
+                       } else {
+                               self.append( html );
+                       }
+               } );
+       },
+
+       wrap: function( html ) {
+               var htmlIsFunction = isFunction( html );
+
+               return this.each( function( i ) {
+                       jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
+               } );
+       },
+
+       unwrap: function( selector ) {
+               this.parent( selector ).not( "body" ).each( function() {
+                       jQuery( this ).replaceWith( this.childNodes );
+               } );
+               return this;
+       }
+} );
+
+
+jQuery.expr.pseudos.hidden = function( elem ) {
+       return !jQuery.expr.pseudos.visible( elem );
+};
+jQuery.expr.pseudos.visible = function( elem ) {
+       return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
+};
+
+
+
+
+jQuery.ajaxSettings.xhr = function() {
+       try {
+               return new window.XMLHttpRequest();
+       } catch ( e ) {}
+};
+
+var xhrSuccessStatus = {
+
+               // File protocol always yields status code 0, assume 200
+               0: 200,
+
+               // Support: IE <=9 only
+               // #1450: sometimes IE returns 1223 when it should be 204
+               1223: 204
+       },
+       xhrSupported = jQuery.ajaxSettings.xhr();
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport( function( options ) {
+       var callback, errorCallback;
+
+       // Cross domain only allowed if supported through XMLHttpRequest
+       if ( support.cors || xhrSupported && !options.crossDomain ) {
+               return {
+                       send: function( headers, complete ) {
+                               var i,
+                                       xhr = options.xhr();
+
+                               xhr.open(
+                                       options.type,
+                                       options.url,
+                                       options.async,
+                                       options.username,
+                                       options.password
+                               );
+
+                               // Apply custom fields if provided
+                               if ( options.xhrFields ) {
+                                       for ( i in options.xhrFields ) {
+                                               xhr[ i ] = options.xhrFields[ i ];
+                                       }
+                               }
+
+                               // Override mime type if needed
+                               if ( options.mimeType && xhr.overrideMimeType ) {
+                                       xhr.overrideMimeType( options.mimeType );
+                               }
+
+                               // X-Requested-With header
+                               // For cross-domain requests, seeing as conditions for a preflight are
+                               // akin to a jigsaw puzzle, we simply never set it to be sure.
+                               // (it can always be set on a per-request basis or even using ajaxSetup)
+                               // For same-domain requests, won't change header if already provided.
+                               if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
+                                       headers[ "X-Requested-With" ] = "XMLHttpRequest";
+                               }
+
+                               // Set headers
+                               for ( i in headers ) {
+                                       xhr.setRequestHeader( i, headers[ i ] );
+                               }
+
+                               // Callback
+                               callback = function( type ) {
+                                       return function() {
+                                               if ( callback ) {
+                                                       callback = errorCallback = xhr.onload =
+                                                               xhr.onerror = xhr.onabort = xhr.ontimeout =
+                                                                       xhr.onreadystatechange = null;
+
+                                                       if ( type === "abort" ) {
+                                                               xhr.abort();
+                                                       } else if ( type === "error" ) {
+
+                                                               // Support: IE <=9 only
+                                                               // On a manual native abort, IE9 throws
+                                                               // errors on any property access that is not readyState
+                                                               if ( typeof xhr.status !== "number" ) {
+                                                                       complete( 0, "error" );
+                                                               } else {
+                                                                       complete(
+
+                                                                               // File: protocol always yields status 0; see #8605, #14207
+                                                                               xhr.status,
+                                                                               xhr.statusText
+                                                                       );
+                                                               }
+                                                       } else {
+                                                               complete(
+                                                                       xhrSuccessStatus[ xhr.status ] || xhr.status,
+                                                                       xhr.statusText,
+
+                                                                       // Support: IE <=9 only
+                                                                       // IE9 has no XHR2 but throws on binary (trac-11426)
+                                                                       // For XHR2 non-text, let the caller handle it (gh-2498)
+                                                                       ( xhr.responseType || "text" ) !== "text"  ||
+                                                                       typeof xhr.responseText !== "string" ?
+                                                                               { binary: xhr.response } :
+                                                                               { text: xhr.responseText },
+                                                                       xhr.getAllResponseHeaders()
+                                                               );
+                                                       }
+                                               }
+                                       };
+                               };
+
+                               // Listen to events
+                               xhr.onload = callback();
+                               errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
+
+                               // Support: IE 9 only
+                               // Use onreadystatechange to replace onabort
+                               // to handle uncaught aborts
+                               if ( xhr.onabort !== undefined ) {
+                                       xhr.onabort = errorCallback;
+                               } else {
+                                       xhr.onreadystatechange = function() {
+
+                                               // Check readyState before timeout as it changes
+                                               if ( xhr.readyState === 4 ) {
+
+                                                       // Allow onerror to be called first,
+                                                       // but that will not handle a native abort
+                                                       // Also, save errorCallback to a variable
+                                                       // as xhr.onerror cannot be accessed
+                                                       window.setTimeout( function() {
+                                                               if ( callback ) {
+                                                                       errorCallback();
+                                                               }
+                                                       } );
+                                               }
+                                       };
+                               }
+
+                               // Create the abort callback
+                               callback = callback( "abort" );
+
+                               try {
+
+                                       // Do send the request (this may raise an exception)
+                                       xhr.send( options.hasContent && options.data || null );
+                               } catch ( e ) {
+
+                                       // #14683: Only rethrow if this hasn't been notified as an error yet
+                                       if ( callback ) {
+                                               throw e;
+                                       }
+                               }
+                       },
+
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+} );
+
+
+
+
+// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
+jQuery.ajaxPrefilter( function( s ) {
+       if ( s.crossDomain ) {
+               s.contents.script = false;
+       }
+} );
+
+// Install script dataType
+jQuery.ajaxSetup( {
+       accepts: {
+               script: "text/javascript, application/javascript, " +
+                       "application/ecmascript, application/x-ecmascript"
+       },
+       contents: {
+               script: /\b(?:java|ecma)script\b/
+       },
+       converters: {
+               "text script": function( text ) {
+                       jQuery.globalEval( text );
+                       return text;
+               }
+       }
+} );
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+       if ( s.cache === undefined ) {
+               s.cache = false;
+       }
+       if ( s.crossDomain ) {
+               s.type = "GET";
+       }
+} );
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+
+       // This transport only deals with cross domain or forced-by-attrs requests
+       if ( s.crossDomain || s.scriptAttrs ) {
+               var script, callback;
+               return {
+                       send: function( _, complete ) {
+                               script = jQuery( "<script>" )
+                                       .attr( s.scriptAttrs || {} )
+                                       .prop( { charset: s.scriptCharset, src: s.url } )
+                                       .on( "load error", callback = function( evt ) {
+                                               script.remove();
+                                               callback = null;
+                                               if ( evt ) {
+                                                       complete( evt.type === "error" ? 404 : 200, evt.type );
+                                               }
+                                       } );
+
+                               // Use native DOM manipulation to avoid our domManip AJAX trickery
+                               document.head.appendChild( script[ 0 ] );
+                       },
+                       abort: function() {
+                               if ( callback ) {
+                                       callback();
+                               }
+                       }
+               };
+       }
+} );
+
+
+
+
+var oldCallbacks = [],
+       rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup( {
+       jsonp: "callback",
+       jsonpCallback: function() {
+               var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
+               this[ callback ] = true;
+               return callback;
+       }
+} );
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+       var callbackName, overwritten, responseContainer,
+               jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+                       "url" :
+                       typeof s.data === "string" &&
+                               ( s.contentType || "" )
+                                       .indexOf( "application/x-www-form-urlencoded" ) === 0 &&
+                               rjsonp.test( s.data ) && "data"
+               );
+
+       // Handle iff the expected data type is "jsonp" or we have a parameter to set
+       if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+               // Get callback name, remembering preexisting value associated with it
+               callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
+                       s.jsonpCallback() :
+                       s.jsonpCallback;
+
+               // Insert callback into url or form data
+               if ( jsonProp ) {
+                       s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+               } else if ( s.jsonp !== false ) {
+                       s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+               }
+
+               // Use data converter to retrieve json after script execution
+               s.converters[ "script json" ] = function() {
+                       if ( !responseContainer ) {
+                               jQuery.error( callbackName + " was not called" );
+                       }
+                       return responseContainer[ 0 ];
+               };
+
+               // Force json dataType
+               s.dataTypes[ 0 ] = "json";
+
+               // Install callback
+               overwritten = window[ callbackName ];
+               window[ callbackName ] = function() {
+                       responseContainer = arguments;
+               };
+
+               // Clean-up function (fires after converters)
+               jqXHR.always( function() {
+
+                       // If previous value didn't exist - remove it
+                       if ( overwritten === undefined ) {
+                               jQuery( window ).removeProp( callbackName );
+
+                       // Otherwise restore preexisting value
+                       } else {
+                               window[ callbackName ] = overwritten;
+                       }
+
+                       // Save back as free
+                       if ( s[ callbackName ] ) {
+
+                               // Make sure that re-using the options doesn't screw things around
+                               s.jsonpCallback = originalSettings.jsonpCallback;
+
+                               // Save the callback name for future use
+                               oldCallbacks.push( callbackName );
+                       }
+
+                       // Call if it was a function and we have a response
+                       if ( responseContainer && isFunction( overwritten ) ) {
+                               overwritten( responseContainer[ 0 ] );
+                       }
+
+                       responseContainer = overwritten = undefined;
+               } );
+
+               // Delegate to script
+               return "script";
+       }
+} );
+
+
+
+
+// Support: Safari 8 only
+// In Safari 8 documents created via document.implementation.createHTMLDocument
+// collapse sibling forms: the second one becomes a child of the first one.
+// Because of that, this security measure has to be disabled in Safari 8.
+// https://bugs.webkit.org/show_bug.cgi?id=137337
+support.createHTMLDocument = ( function() {
+       var body = document.implementation.createHTMLDocument( "" ).body;
+       body.innerHTML = "<form></form><form></form>";
+       return body.childNodes.length === 2;
+} )();
+
+
+// Argument "data" should be string of html
+// context (optional): If specified, the fragment will be created in this context,
+// defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+       if ( typeof data !== "string" ) {
+               return [];
+       }
+       if ( typeof context === "boolean" ) {
+               keepScripts = context;
+               context = false;
+       }
+
+       var base, parsed, scripts;
+
+       if ( !context ) {
+
+               // Stop scripts or inline event handlers from being executed immediately
+               // by using document.implementation
+               if ( support.createHTMLDocument ) {
+                       context = document.implementation.createHTMLDocument( "" );
+
+                       // Set the base href for the created document
+                       // so any parsed elements with URLs
+                       // are based on the document's URL (gh-2965)
+                       base = context.createElement( "base" );
+                       base.href = document.location.href;
+                       context.head.appendChild( base );
+               } else {
+                       context = document;
+               }
+       }
+
+       parsed = rsingleTag.exec( data );
+       scripts = !keepScripts && [];
+
+       // Single tag
+       if ( parsed ) {
+               return [ context.createElement( parsed[ 1 ] ) ];
+       }
+
+       parsed = buildFragment( [ data ], context, scripts );
+
+       if ( scripts && scripts.length ) {
+               jQuery( scripts ).remove();
+       }
+
+       return jQuery.merge( [], parsed.childNodes );
+};
+
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+       var selector, type, response,
+               self = this,
+               off = url.indexOf( " " );
+
+       if ( off > -1 ) {
+               selector = stripAndCollapse( url.slice( off ) );
+               url = url.slice( 0, off );
+       }
+
+       // If it's a function
+       if ( isFunction( params ) ) {
+
+               // We assume that it's the callback
+               callback = params;
+               params = undefined;
+
+       // Otherwise, build a param string
+       } else if ( params && typeof params === "object" ) {
+               type = "POST";
+       }
+
+       // If we have elements to modify, make the request
+       if ( self.length > 0 ) {
+               jQuery.ajax( {
+                       url: url,
+
+                       // If "type" variable is undefined, then "GET" method will be used.
+                       // Make value of this field explicit since
+                       // user can override it through ajaxSetup method
+                       type: type || "GET",
+                       dataType: "html",
+                       data: params
+               } ).done( function( responseText ) {
+
+                       // Save response for use in complete callback
+                       response = arguments;
+
+                       self.html( selector ?
+
+                               // If a selector was specified, locate the right elements in a dummy div
+                               // Exclude scripts to avoid IE 'Permission Denied' errors
+                               jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+                               // Otherwise use the full result
+                               responseText );
+
+               // If the request succeeds, this function gets "data", "status", "jqXHR"
+               // but they are ignored because response was set above.
+               // If it fails, this function gets "jqXHR", "status", "error"
+               } ).always( callback && function( jqXHR, status ) {
+                       self.each( function() {
+                               callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
+                       } );
+               } );
+       }
+
+       return this;
+};
+
+
+
+
+jQuery.expr.pseudos.animated = function( elem ) {
+       return jQuery.grep( jQuery.timers, function( fn ) {
+               return elem === fn.elem;
+       } ).length;
+};
+
+
+
+
+jQuery.offset = {
+       setOffset: function( elem, options, i ) {
+               var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+                       position = jQuery.css( elem, "position" ),
+                       curElem = jQuery( elem ),
+                       props = {};
+
+               // Set position first, in-case top/left are set even on static elem
+               if ( position === "static" ) {
+                       elem.style.position = "relative";
+               }
+
+               curOffset = curElem.offset();
+               curCSSTop = jQuery.css( elem, "top" );
+               curCSSLeft = jQuery.css( elem, "left" );
+               calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+                       ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
+
+               // Need to be able to calculate position if either
+               // top or left is auto and position is either absolute or fixed
+               if ( calculatePosition ) {
+                       curPosition = curElem.position();
+                       curTop = curPosition.top;
+                       curLeft = curPosition.left;
+
+               } else {
+                       curTop = parseFloat( curCSSTop ) || 0;
+                       curLeft = parseFloat( curCSSLeft ) || 0;
+               }
+
+               if ( isFunction( options ) ) {
+
+                       // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+                       options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
+               }
+
+               if ( options.top != null ) {
+                       props.top = ( options.top - curOffset.top ) + curTop;
+               }
+               if ( options.left != null ) {
+                       props.left = ( options.left - curOffset.left ) + curLeft;
+               }
+
+               if ( "using" in options ) {
+                       options.using.call( elem, props );
+
+               } else {
+                       if ( typeof props.top === "number" ) {
+                               props.top += "px";
+                       }
+                       if ( typeof props.left === "number" ) {
+                               props.left += "px";
+                       }
+                       curElem.css( props );
+               }
+       }
+};
+
+jQuery.fn.extend( {
+
+       // offset() relates an element's border box to the document origin
+       offset: function( options ) {
+
+               // Preserve chaining for setter
+               if ( arguments.length ) {
+                       return options === undefined ?
+                               this :
+                               this.each( function( i ) {
+                                       jQuery.offset.setOffset( this, options, i );
+                               } );
+               }
+
+               var rect, win,
+                       elem = this[ 0 ];
+
+               if ( !elem ) {
+                       return;
+               }
+
+               // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
+               // Support: IE <=11 only
+               // Running getBoundingClientRect on a
+               // disconnected node in IE throws an error
+               if ( !elem.getClientRects().length ) {
+                       return { top: 0, left: 0 };
+               }
+
+               // Get document-relative position by adding viewport scroll to viewport-relative gBCR
+               rect = elem.getBoundingClientRect();
+               win = elem.ownerDocument.defaultView;
+               return {
+                       top: rect.top + win.pageYOffset,
+                       left: rect.left + win.pageXOffset
+               };
+       },
+
+       // position() relates an element's margin box to its offset parent's padding box
+       // This corresponds to the behavior of CSS absolute positioning
+       position: function() {
+               if ( !this[ 0 ] ) {
+                       return;
+               }
+
+               var offsetParent, offset, doc,
+                       elem = this[ 0 ],
+                       parentOffset = { top: 0, left: 0 };
+
+               // position:fixed elements are offset from the viewport, which itself always has zero offset
+               if ( jQuery.css( elem, "position" ) === "fixed" ) {
+
+                       // Assume position:fixed implies availability of getBoundingClientRect
+                       offset = elem.getBoundingClientRect();
+
+               } else {
+                       offset = this.offset();
+
+                       // Account for the *real* offset parent, which can be the document or its root element
+                       // when a statically positioned element is identified
+                       doc = elem.ownerDocument;
+                       offsetParent = elem.offsetParent || doc.documentElement;
+                       while ( offsetParent &&
+                               ( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
+                               jQuery.css( offsetParent, "position" ) === "static" ) {
+
+                               offsetParent = offsetParent.parentNode;
+                       }
+                       if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
+
+                               // Incorporate borders into its offset, since they are outside its content origin
+                               parentOffset = jQuery( offsetParent ).offset();
+                               parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
+                               parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
+                       }
+               }
+
+               // Subtract parent offsets and element margins
+               return {
+                       top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+                       left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+               };
+       },
+
+       // This method will return documentElement in the following cases:
+       // 1) For the element inside the iframe without offsetParent, this method will return
+       //    documentElement of the parent window
+       // 2) For the hidden or detached element
+       // 3) For body or html element, i.e. in case of the html node - it will return itself
+       //
+       // but those exceptions were never presented as a real life use-cases
+       // and might be considered as more preferable results.
+       //
+       // This logic, however, is not guaranteed and can change at any point in the future
+       offsetParent: function() {
+               return this.map( function() {
+                       var offsetParent = this.offsetParent;
+
+                       while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
+                               offsetParent = offsetParent.offsetParent;
+                       }
+
+                       return offsetParent || documentElement;
+               } );
+       }
+} );
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+       var top = "pageYOffset" === prop;
+
+       jQuery.fn[ method ] = function( val ) {
+               return access( this, function( elem, method, val ) {
+
+                       // Coalesce documents and windows
+                       var win;
+                       if ( isWindow( elem ) ) {
+                               win = elem;
+                       } else if ( elem.nodeType === 9 ) {
+                               win = elem.defaultView;
+                       }
+
+                       if ( val === undefined ) {
+                               return win ? win[ prop ] : elem[ method ];
+                       }
+
+                       if ( win ) {
+                               win.scrollTo(
+                                       !top ? val : win.pageXOffset,
+                                       top ? val : win.pageYOffset
+                               );
+
+                       } else {
+                               elem[ method ] = val;
+                       }
+               }, method, val, arguments.length );
+       };
+} );
+
+// Support: Safari <=7 - 9.1, Chrome <=37 - 49
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( _i, prop ) {
+       jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+               function( elem, computed ) {
+                       if ( computed ) {
+                               computed = curCSS( elem, prop );
+
+                               // If curCSS returns percentage, fallback to offset
+                               return rnumnonpx.test( computed ) ?
+                                       jQuery( elem ).position()[ prop ] + "px" :
+                                       computed;
+                       }
+               }
+       );
+} );
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+       jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
+               function( defaultExtra, funcName ) {
+
+               // Margin is only for outerHeight, outerWidth
+               jQuery.fn[ funcName ] = function( margin, value ) {
+                       var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+                               extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+                       return access( this, function( elem, type, value ) {
+                               var doc;
+
+                               if ( isWindow( elem ) ) {
+
+                                       // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
+                                       return funcName.indexOf( "outer" ) === 0 ?
+                                               elem[ "inner" + name ] :
+                                               elem.document.documentElement[ "client" + name ];
+                               }
+
+                               // Get document width or height
+                               if ( elem.nodeType === 9 ) {
+                                       doc = elem.documentElement;
+
+                                       // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+                                       // whichever is greatest
+                                       return Math.max(
+                                               elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+                                               elem.body[ "offset" + name ], doc[ "offset" + name ],
+                                               doc[ "client" + name ]
+                                       );
+                               }
+
+                               return value === undefined ?
+
+                                       // Get width or height on the element, requesting but not forcing parseFloat
+                                       jQuery.css( elem, type, extra ) :
+
+                                       // Set width or height on the element
+                                       jQuery.style( elem, type, value, extra );
+                       }, type, chainable ? margin : undefined, chainable );
+               };
+       } );
+} );
+
+
+jQuery.each( [
+       "ajaxStart",
+       "ajaxStop",
+       "ajaxComplete",
+       "ajaxError",
+       "ajaxSuccess",
+       "ajaxSend"
+], function( _i, type ) {
+       jQuery.fn[ type ] = function( fn ) {
+               return this.on( type, fn );
+       };
+} );
+
+
+
+
+jQuery.fn.extend( {
+
+       bind: function( types, data, fn ) {
+               return this.on( types, null, data, fn );
+       },
+       unbind: function( types, fn ) {
+               return this.off( types, null, fn );
+       },
+
+       delegate: function( selector, types, data, fn ) {
+               return this.on( types, selector, data, fn );
+       },
+       undelegate: function( selector, types, fn ) {
+
+               // ( namespace ) or ( selector, types [, fn] )
+               return arguments.length === 1 ?
+                       this.off( selector, "**" ) :
+                       this.off( types, selector || "**", fn );
+       },
+
+       hover: function( fnOver, fnOut ) {
+               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+       }
+} );
+
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+       "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+       function( _i, name ) {
+
+               // Handle event binding
+               jQuery.fn[ name ] = function( data, fn ) {
+                       return arguments.length > 0 ?
+                               this.on( name, null, data, fn ) :
+                               this.trigger( name );
+               };
+       } );
+
+
+
+
+// Support: Android <=4.0 only
+// Make sure we trim BOM and NBSP
+var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+
+// Bind a function to a context, optionally partially applying any
+// arguments.
+// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
+// However, it is not slated for removal any time soon
+jQuery.proxy = function( fn, context ) {
+       var tmp, args, proxy;
+
+       if ( typeof context === "string" ) {
+               tmp = fn[ context ];
+               context = fn;
+               fn = tmp;
+       }
+
+       // Quick check to determine if target is callable, in the spec
+       // this throws a TypeError, but we will just return undefined.
+       if ( !isFunction( fn ) ) {
+               return undefined;
+       }
+
+       // Simulated bind
+       args = slice.call( arguments, 2 );
+       proxy = function() {
+               return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+       };
+
+       // Set the guid of unique handler to the same of original handler, so it can be removed
+       proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+       return proxy;
+};
+
+jQuery.holdReady = function( hold ) {
+       if ( hold ) {
+               jQuery.readyWait++;
+       } else {
+               jQuery.ready( true );
+       }
+};
+jQuery.isArray = Array.isArray;
+jQuery.parseJSON = JSON.parse;
+jQuery.nodeName = nodeName;
+jQuery.isFunction = isFunction;
+jQuery.isWindow = isWindow;
+jQuery.camelCase = camelCase;
+jQuery.type = toType;
+
+jQuery.now = Date.now;
+
+jQuery.isNumeric = function( obj ) {
+
+       // As of jQuery 3.0, isNumeric is limited to
+       // strings and numbers (primitives or objects)
+       // that can be coerced to finite numbers (gh-2662)
+       var type = jQuery.type( obj );
+       return ( type === "number" || type === "string" ) &&
+
+               // parseFloat NaNs numeric-cast false positives ("")
+               // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+               // subtraction forces infinities to NaN
+               !isNaN( obj - parseFloat( obj ) );
+};
+
+jQuery.trim = function( text ) {
+       return text == null ?
+               "" :
+               ( text + "" ).replace( rtrim, "" );
+};
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+       define( "jquery", [], function() {
+               return jQuery;
+       } );
+}
+
+
+
+
+var
+
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+
+       // Map over the $ in case of overwrite
+       _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+       if ( window.$ === jQuery ) {
+               window.$ = _$;
+       }
+
+       if ( deep && window.jQuery === jQuery ) {
+               window.jQuery = _jQuery;
+       }
+
+       return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === "undefined" ) {
+       window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+} );
diff --git a/java/doc/jquery/jquery-3.6.0.min.js b/java/doc/jquery/jquery-3.6.0.min.js
new file mode 100644 (file)
index 0000000..c4c6022
--- /dev/null
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
diff --git a/java/doc/jquery/jquery-ui.min.css b/java/doc/jquery/jquery-ui.min.css
new file mode 100644 (file)
index 0000000..d64539c
--- /dev/null
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.13.1 - 2022-05-12
+* http://jqueryui.com
+* Includes: core.css, autocomplete.css, menu.css
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}
\ No newline at end of file
diff --git a/java/doc/jquery/jquery-ui.min.js b/java/doc/jquery/jquery-ui.min.js
new file mode 100644 (file)
index 0000000..55c2832
--- /dev/null
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.13.1 - 2022-05-12
+* http://jqueryui.com
+* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(x){"use strict";x.ui=x.ui||{};x.ui.version="1.13.1";var n,i=0,l=Array.prototype.hasOwnProperty,a=Array.prototype.slice;x.cleanData=(n=x.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=x._data(i,"events"))&&e.remove&&x(i).triggerHandler("remove");n(t)}),x.widget=function(t,i,e){var s,n,o,l={},a=t.split(".")[0],r=a+"-"+(t=t.split(".")[1]);return e||(e=i,i=x.Widget),Array.isArray(e)&&(e=x.extend.apply(null,[{}].concat(e))),x.expr.pseudos[r.toLowerCase()]=function(t){return!!x.data(t,r)},x[a]=x[a]||{},s=x[a][t],n=x[a][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},x.extend(n,s,{version:e.version,_proto:x.extend({},e),_childConstructors:[]}),(o=new i).options=x.widget.extend({},o.options),x.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}l[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),n.prototype=x.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},l,{constructor:n,namespace:a,widgetName:t,widgetFullName:r}),s?(x.each(s._childConstructors,function(t,e){var i=e.prototype;x.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),x.widget.bridge(t,n),n},x.widget.extend=function(t){for(var e,i,s=a.call(arguments,1),n=0,o=s.length;n<o;n++)for(e in s[n])i=s[n][e],l.call(s[n],e)&&void 0!==i&&(x.isPlainObject(i)?t[e]=x.isPlainObject(t[e])?x.widget.extend({},t[e],i):x.widget.extend({},i):t[e]=i);return t},x.widget.bridge=function(o,e){var l=e.prototype.widgetFullName||o;x.fn[o]=function(i){var t="string"==typeof i,s=a.call(arguments,1),n=this;return t?this.length||"instance"!==i?this.each(function(){var t,e=x.data(this,l);return"instance"===i?(n=e,!1):e?"function"!=typeof e[i]||"_"===i.charAt(0)?x.error("no such method '"+i+"' for "+o+" widget instance"):(t=e[i].apply(e,s))!==e&&void 0!==t?(n=t&&t.jquery?n.pushStack(t.get()):t,!1):void 0:x.error("cannot call methods on "+o+" prior to initialization; attempted to call method '"+i+"'")}):n=void 0:(s.length&&(i=x.widget.extend.apply(null,[i].concat(s))),this.each(function(){var t=x.data(this,l);t?(t.option(i||{}),t._init&&t._init()):x.data(this,l,new e(i,this))})),n}},x.Widget=function(){},x.Widget._childConstructors=[],x.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=x(e||this.defaultElement||this)[0],this.element=x(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=x(),this.hoverable=x(),this.focusable=x(),this.classesElementLookup={},e!==this&&(x.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=x(e.style?e.ownerDocument:e.document||e),this.window=x(this.document[0].defaultView||this.document[0].parentWindow)),this.options=x.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:x.noop,_create:x.noop,_init:x.noop,destroy:function(){var i=this;this._destroy(),x.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:x.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return x.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=x.widget.extend({},this.options[t]),n=0;n<i.length-1;n++)s[i[n]]=s[i[n]]||{},s=s[i[n]];if(t=i.pop(),1===arguments.length)return void 0===s[t]?null:s[t];s[t]=e}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];o[t]=e}return this._setOptions(o),this},_setOptions:function(t){for(var e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(t){var e,i,s;for(e in t)s=this.classesElementLookup[e],t[e]!==this.options.classes[e]&&s&&s.length&&(i=x(s.get()),this._removeClass(s,e),i.addClass(this._classes({element:i,keys:e,classes:t,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(n){var o=[],l=this;function t(t,e){for(var i,s=0;s<t.length;s++)i=l.classesElementLookup[t[s]]||x(),i=n.add?(function(){var i=[];n.element.each(function(t,e){x.map(l.classesElementLookup,function(t){return t}).some(function(t){return t.is(e)})||i.push(e)}),l._on(x(i),{remove:"_untrackClassesElement"})}(),x(x.uniqueSort(i.get().concat(n.element.get())))):x(i.not(n.element).get()),l.classesElementLookup[t[s]]=i,o.push(t[s]),e&&n.classes[t[s]]&&o.push(n.classes[t[s]])}return(n=x.extend({element:this.element,classes:this.options.classes||{}},n)).keys&&t(n.keys.match(/\S+/g)||[],!0),n.extra&&t(n.extra.match(/\S+/g)||[]),o.join(" ")},_untrackClassesElement:function(i){var s=this;x.each(s.classesElementLookup,function(t,e){-1!==x.inArray(i.target,e)&&(s.classesElementLookup[t]=x(e.not(i.target).get()))}),this._off(x(i.target))},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){var n="string"==typeof t||null===t,i={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s="boolean"==typeof s?s:i};return i.element.toggleClass(this._classes(i),s),this},_on:function(n,o,t){var l,a=this;"boolean"!=typeof n&&(t=o,o=n,n=!1),t?(o=l=x(o),this.bindings=this.bindings.add(o)):(t=o,o=this.element,l=this.widget()),x.each(t,function(t,e){function i(){if(n||!0!==a.options.disabled&&!x(this).hasClass("ui-state-disabled"))return("string"==typeof e?a[e]:e).apply(a,arguments)}"string"!=typeof e&&(i.guid=e.guid=e.guid||i.guid||x.guid++);var s=t.match(/^([\w:-]*)\s*(.*)$/),t=s[1]+a.eventNamespace,s=s[2];s?l.on(t,s,i):o.on(t,i)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.off(e),this.bindings=x(this.bindings.not(t).get()),this.focusable=x(this.focusable.not(t).get()),this.hoverable=x(this.hoverable.not(t).get())},_delay:function(t,e){var i=this;return setTimeout(function(){return("string"==typeof t?i[t]:t).apply(i,arguments)},e||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){this._addClass(x(t.currentTarget),null,"ui-state-hover")},mouseleave:function(t){this._removeClass(x(t.currentTarget),null,"ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){this._addClass(x(t.currentTarget),null,"ui-state-focus")},focusout:function(t){this._removeClass(x(t.currentTarget),null,"ui-state-focus")}})},_trigger:function(t,e,i){var s,n,o=this.options[t];if(i=i||{},(e=x.Event(e)).type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),e.target=this.element[0],n=e.originalEvent)for(s in n)s in e||(e[s]=n[s]);return this.element.trigger(e,i),!("function"==typeof o&&!1===o.apply(this.element[0],[e].concat(i))||e.isDefaultPrevented())}},x.each({show:"fadeIn",hide:"fadeOut"},function(o,l){x.Widget.prototype["_"+o]=function(e,t,i){var s,n=(t="string"==typeof t?{effect:t}:t)?!0!==t&&"number"!=typeof t&&t.effect||l:o;"number"==typeof(t=t||{})?t={duration:t}:!0===t&&(t={}),s=!x.isEmptyObject(t),t.complete=i,t.delay&&e.delay(t.delay),s&&x.effects&&x.effects.effect[n]?e[o](t):n!==o&&e[n]?e[n](t.duration,t.easing,i):e.queue(function(t){x(this)[o](),i&&i.call(e[0]),t()})}});var s,C,E,o,r,u,h,c,k;x.widget;function T(t,e,i){return[parseFloat(t[0])*(c.test(t[0])?e/100:1),parseFloat(t[1])*(c.test(t[1])?i/100:1)]}function A(t,e){return parseInt(x.css(t,e),10)||0}function W(t){return null!=t&&t===t.window}C=Math.max,E=Math.abs,o=/left|center|right/,r=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,h=/^\w+/,c=/%$/,k=x.fn.position,x.position={scrollbarWidth:function(){if(void 0!==s)return s;var t,e=x("<div style='display:block;position:absolute;width:200px;height:200px;overflow:hidden;'><div style='height:300px;width:auto;'></div></div>"),i=e.children()[0];return x("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.width<t.element[0].scrollWidth;return{width:"scroll"===i||"auto"===i&&t.height<t.element[0].scrollHeight?x.position.scrollbarWidth():0,height:e?x.position.scrollbarWidth():0}},getWithinInfo:function(t){var e=x(t||window),i=W(e[0]),s=!!e[0]&&9===e[0].nodeType;return{element:e,isWindow:i,isDocument:s,offset:!i&&!s?x(t).offset():{left:0,top:0},scrollLeft:e.scrollLeft(),scrollTop:e.scrollTop(),width:e.outerWidth(),height:e.outerHeight()}}},x.fn.position=function(c){if(!c||!c.of)return k.apply(this,arguments);var d,f,m,p,v,t,g="string"==typeof(c=x.extend({},c)).of?x(document).find(c.of):x(c.of),_=x.position.getWithinInfo(c.within),y=x.position.getScrollInfo(_),b=(c.collision||"flip").split(" "),w={},e=9===(t=(e=g)[0]).nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:W(t)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:t.preventDefault?{width:0,height:0,offset:{top:t.pageY,left:t.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()};return g[0].preventDefault&&(c.at="left top"),f=e.width,m=e.height,v=x.extend({},p=e.offset),x.each(["my","at"],function(){var t,e,i=(c[this]||"").split(" ");(i=1===i.length?o.test(i[0])?i.concat(["center"]):r.test(i[0])?["center"].concat(i):["center","center"]:i)[0]=o.test(i[0])?i[0]:"center",i[1]=r.test(i[1])?i[1]:"center",t=u.exec(i[0]),e=u.exec(i[1]),w[this]=[t?t[0]:0,e?e[0]:0],c[this]=[h.exec(i[0])[0],h.exec(i[1])[0]]}),1===b.length&&(b[1]=b[0]),"right"===c.at[0]?v.left+=f:"center"===c.at[0]&&(v.left+=f/2),"bottom"===c.at[1]?v.top+=m:"center"===c.at[1]&&(v.top+=m/2),d=T(w.at,f,m),v.left+=d[0],v.top+=d[1],this.each(function(){var i,t,l=x(this),a=l.outerWidth(),r=l.outerHeight(),e=A(this,"marginLeft"),s=A(this,"marginTop"),n=a+e+A(this,"marginRight")+y.width,o=r+s+A(this,"marginBottom")+y.height,u=x.extend({},v),h=T(w.my,l.outerWidth(),l.outerHeight());"right"===c.my[0]?u.left-=a:"center"===c.my[0]&&(u.left-=a/2),"bottom"===c.my[1]?u.top-=r:"center"===c.my[1]&&(u.top-=r/2),u.left+=h[0],u.top+=h[1],i={marginLeft:e,marginTop:s},x.each(["left","top"],function(t,e){x.ui.position[b[t]]&&x.ui.position[b[t]][e](u,{targetWidth:f,targetHeight:m,elemWidth:a,elemHeight:r,collisionPosition:i,collisionWidth:n,collisionHeight:o,offset:[d[0]+h[0],d[1]+h[1]],my:c.my,at:c.at,within:_,elem:l})}),c.using&&(t=function(t){var e=p.left-u.left,i=e+f-a,s=p.top-u.top,n=s+m-r,o={target:{element:g,left:p.left,top:p.top,width:f,height:m},element:{element:l,left:u.left,top:u.top,width:a,height:r},horizontal:i<0?"left":0<e?"right":"center",vertical:n<0?"top":0<s?"bottom":"middle"};f<a&&E(e+i)<f&&(o.horizontal="center"),m<r&&E(s+n)<m&&(o.vertical="middle"),C(E(e),E(i))>C(E(s),E(n))?o.important="horizontal":o.important="vertical",c.using.call(this,t,o)}),l.offset(x.extend(u,{using:t}))})},x.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,l=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0<l&&a<=0?(i=t.left+l+e.collisionWidth-n-s,t.left+=l-i):t.left=!(0<a&&l<=0)&&a<l?s+n-e.collisionWidth:s:0<l?t.left+=l:0<a?t.left-=a:t.left=C(t.left-o,t.left)},top:function(t,e){var i=e.within,s=i.isWindow?i.scrollTop:i.offset.top,n=e.within.height,o=t.top-e.collisionPosition.marginTop,l=s-o,a=o+e.collisionHeight-n-s;e.collisionHeight>n?0<l&&a<=0?(i=t.top+l+e.collisionHeight-n-s,t.top+=l-i):t.top=!(0<a&&l<=0)&&a<l?s+n-e.collisionHeight:s:0<l?t.top+=l:0<a?t.top-=a:t.top=C(t.top-o,t.top)}},flip:{left:function(t,e){var i=e.within,s=i.offset.left+i.scrollLeft,n=i.width,o=i.isWindow?i.scrollLeft:i.offset.left,l=t.left-e.collisionPosition.marginLeft,a=l-o,r=l+e.collisionWidth-n-o,u="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,i="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,l=-2*e.offset[0];a<0?((s=t.left+u+i+l+e.collisionWidth-n-s)<0||s<E(a))&&(t.left+=u+i+l):0<r&&(0<(o=t.left-e.collisionPosition.marginLeft+u+i+l-o)||E(o)<r)&&(t.left+=u+i+l)},top:function(t,e){var i=e.within,s=i.offset.top+i.scrollTop,n=i.height,o=i.isWindow?i.scrollTop:i.offset.top,l=t.top-e.collisionPosition.marginTop,a=l-o,r=l+e.collisionHeight-n-o,u="top"===e.my[1]?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,i="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,l=-2*e.offset[1];a<0?((s=t.top+u+i+l+e.collisionHeight-n-s)<0||s<E(a))&&(t.top+=u+i+l):0<r&&(0<(o=t.top-e.collisionPosition.marginTop+u+i+l-o)||E(o)<r)&&(t.top+=u+i+l)}},flipfit:{left:function(){x.ui.position.flip.left.apply(this,arguments),x.ui.position.fit.left.apply(this,arguments)},top:function(){x.ui.position.flip.top.apply(this,arguments),x.ui.position.fit.top.apply(this,arguments)}}};var t;x.ui.position,x.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},x.fn.extend({uniqueId:(t=0,function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&x(this).removeAttr("id")})}}),x.ui.safeActiveElement=function(e){var i;try{i=e.activeElement}catch(t){i=e.body}return i=!(i=i||e.body).nodeName?e.body:i},x.widget("ui.menu",{version:"1.13.1",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.lastMousePosition={x:null,y:null},this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault(),this._activateItem(t)},"click .ui-menu-item":function(t){var e=x(t.target),i=x(x.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&e.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),e.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&i.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":"_activateItem","mousemove .ui-menu-item":"_activateItem",mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this._menuItems().first();e||this.focus(t,i)},blur:function(t){this._delay(function(){x.contains(this.element[0],x.ui.safeActiveElement(this.document[0]))||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t,!0),this.mouseHandled=!1}})},_activateItem:function(t){var e,i;this.previousFilter||t.clientX===this.lastMousePosition.x&&t.clientY===this.lastMousePosition.y||(this.lastMousePosition={x:t.clientX,y:t.clientY},e=x(t.target).closest(".ui-menu-item"),i=x(t.currentTarget),e[0]===i[0]&&(i.is(".ui-state-active")||(this._removeClass(i.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(t,i))))},_destroy:function(){var t=this.element.find(".ui-menu-item").removeAttr("role aria-disabled").children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),t.children().each(function(){var t=x(this);t.data("ui-menu-submenu-caret")&&t.remove()})},_keydown:function(t){var e,i,s,n=!0;switch(t.keyCode){case x.ui.keyCode.PAGE_UP:this.previousPage(t);break;case x.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case x.ui.keyCode.HOME:this._move("first","first",t);break;case x.ui.keyCode.END:this._move("last","last",t);break;case x.ui.keyCode.UP:this.previous(t);break;case x.ui.keyCode.DOWN:this.next(t);break;case x.ui.keyCode.LEFT:this.collapse(t);break;case x.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case x.ui.keyCode.ENTER:case x.ui.keyCode.SPACE:this._activate(t);break;case x.ui.keyCode.ESCAPE:this.collapse(t);break;default:e=this.previousFilter||"",s=n=!1,i=96<=t.keyCode&&t.keyCode<=105?(t.keyCode-96).toString():String.fromCharCode(t.keyCode),clearTimeout(this.filterTimer),i===e?s=!0:i=e+i,e=this._filterMenuItems(i),(e=s&&-1!==e.index(this.active.next())?this.active.nextAll(".ui-menu-item"):e).length||(i=String.fromCharCode(t.keyCode),e=this._filterMenuItems(i)),e.length?(this.focus(t,e),this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}n&&t.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var t,e,s=this,n=this.options.icons.submenu,i=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),e=i.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=x(this),e=t.prev(),i=x("<span>").data("ui-menu-submenu-caret",!0);s._addClass(i,"ui-menu-icon","ui-icon "+n),e.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",e.attr("id"))}),this._addClass(e,"ui-menu","ui-widget ui-widget-content ui-front"),(t=i.add(this.element).find(this.options.items)).not(".ui-menu-item").each(function(){var t=x(this);s._isDivider(t)&&s._addClass(t,"ui-menu-divider","ui-widget-content")}),i=(e=t.not(".ui-menu-item, .ui-menu-divider")).children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(e,"ui-menu-item")._addClass(i,"ui-menu-item-wrapper"),t.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!x.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){var i;"icons"===t&&(i=this.element.find(".ui-menu-icon"),this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",String(t)),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),i=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),(i=e.children(".ui-menu")).length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(t){var e,i,s;this._hasScroll()&&(i=parseFloat(x.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(x.css(this.activeMenu[0],"paddingTop"))||0,e=t.offset().top-this.activeMenu.offset().top-i-s,i=this.activeMenu.scrollTop(),s=this.activeMenu.height(),t=t.outerHeight(),e<0?this.activeMenu.scrollTop(i+e):s<e+t&&this.activeMenu.scrollTop(i+e-s+t))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this._removeClass(this.active.children(".ui-menu-item-wrapper"),null,"ui-state-active"),this._trigger("blur",t,{item:this.active}),this.active=null)},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(t){var e=x.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(e)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var t=i?this.element:x(e&&e.target).closest(this.element.find(".ui-menu"));t.length||(t=this.element),this._close(t),this.blur(e),this._removeClass(t.find(".ui-state-active"),null,"ui-state-active"),this.activeMenu=t},i?0:this.delay)},_close:function(t){(t=t||(this.active?this.active.parent():this.element)).find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false")},_closeOnDocumentClick:function(t){return!x(t.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this._menuItems(this.active.children(".ui-menu")).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_menuItems:function(t){return(t||this.element).find(this.options.items).filter(".ui-menu-item")},_move:function(t,e,i){var s;(s=this.active?"first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").last():this.active[t+"All"](".ui-menu-item").first():s)&&s.length&&this.active||(s=this._menuItems(this.activeMenu)[e]()),this.focus(i,s)},nextPage:function(t){var e,i,s;this.active?this.isLastItem()||(this._hasScroll()?(i=this.active.offset().top,s=this.element.innerHeight(),0===x.fn.jquery.indexOf("3.2.")&&(s+=this.element[0].offsetHeight-this.element.outerHeight()),this.active.nextAll(".ui-menu-item").each(function(){return(e=x(this)).offset().top-i-s<0}),this.focus(t,e)):this.focus(t,this._menuItems(this.activeMenu)[this.active?"last":"first"]())):this.next(t)},previousPage:function(t){var e,i,s;this.active?this.isFirstItem()||(this._hasScroll()?(i=this.active.offset().top,s=this.element.innerHeight(),0===x.fn.jquery.indexOf("3.2.")&&(s+=this.element[0].offsetHeight-this.element.outerHeight()),this.active.prevAll(".ui-menu-item").each(function(){return 0<(e=x(this)).offset().top-i+s}),this.focus(t,e)):this.focus(t,this._menuItems(this.activeMenu).first())):this.next(t)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(t){this.active=this.active||x(t.target).closest(".ui-menu-item");var e={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(t,!0),this._trigger("select",t,e)},_filterMenuItems:function(t){var t=t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"),e=new RegExp("^"+t,"i");return this.activeMenu.find(this.options.items).filter(".ui-menu-item").filter(function(){return e.test(String.prototype.trim.call(x(this).children(".ui-menu-item-wrapper").text()))})}});x.widget("ui.autocomplete",{version:"1.13.1",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,liveRegionTimer:null,_create:function(){var i,s,n,t=this.element[0].nodeName.toLowerCase(),e="textarea"===t,t="input"===t;this.isMultiLine=e||!t&&this._isContentEditable(this.element),this.valueMethod=this.element[e||t?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(t){if(this.element.prop("readOnly"))s=n=i=!0;else{s=n=i=!1;var e=x.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:i=!0,this._move("previousPage",t);break;case e.PAGE_DOWN:i=!0,this._move("nextPage",t);break;case e.UP:i=!0,this._keyEvent("previous",t);break;case e.DOWN:i=!0,this._keyEvent("next",t);break;case e.ENTER:this.menu.active&&(i=!0,t.preventDefault(),this.menu.select(t));break;case e.TAB:this.menu.active&&this.menu.select(t);break;case e.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(t),t.preventDefault());break;default:s=!0,this._searchTimeout(t)}}},keypress:function(t){if(i)return i=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||t.preventDefault());if(!s){var e=x.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:this._move("previousPage",t);break;case e.PAGE_DOWN:this._move("nextPage",t);break;case e.UP:this._keyEvent("previous",t);break;case e.DOWN:this._keyEvent("next",t)}}},input:function(t){if(n)return n=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){clearTimeout(this.searching),this.close(t),this._change(t)}}),this._initSource(),this.menu=x("<ul>").appendTo(this._appendTo()).menu({role:null}).hide().attr({unselectable:"on"}).menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(t){t.preventDefault()},menufocus:function(t,e){var i,s;if(this.isNewMenu&&(this.isNewMenu=!1,t.originalEvent&&/^mouse/.test(t.originalEvent.type)))return this.menu.blur(),void this.document.one("mousemove",function(){x(t.target).trigger(t.originalEvent)});s=e.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",t,{item:s})&&t.originalEvent&&/^key/.test(t.originalEvent.type)&&this._value(s.value),(i=e.item.attr("aria-label")||s.value)&&String.prototype.trim.call(i).length&&(clearTimeout(this.liveRegionTimer),this.liveRegionTimer=this._delay(function(){this.liveRegion.html(x("<div>").text(i))},100))},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==x.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=x("<div>",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(t){var e=this.menu.element[0];return t.target===this.element[0]||t.target===e||x.contains(e,t.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var t=this.options.appendTo;return t=!(t=!(t=t&&(t.jquery||t.nodeType?x(t):this.document.find(t).eq(0)))||!t[0]?this.element.closest(".ui-front, dialog"):t).length?this.document[0].body:t},_initSource:function(){var i,s,n=this;Array.isArray(this.options.source)?(i=this.options.source,this.source=function(t,e){e(x.ui.autocomplete.filter(i,t.term))}):"string"==typeof this.options.source?(s=this.options.source,this.source=function(t,e){n.xhr&&n.xhr.abort(),n.xhr=x.ajax({url:s,data:t,dataType:"json",success:function(t){e(t)},error:function(){e([])}})}):this.source=this.options.source},_searchTimeout:function(s){clearTimeout(this.searching),this.searching=this._delay(function(){var t=this.term===this._value(),e=this.menu.element.is(":visible"),i=s.altKey||s.ctrlKey||s.metaKey||s.shiftKey;t&&(e||i)||(this.selectedItem=null,this.search(null,s))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):!1!==this._trigger("search",e)?this._search(t):void 0},_search:function(t){this.pending++,this._addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var e=++this.requestIndex;return function(t){e===this.requestIndex&&this.__response(t),this.pending--,this.pending||this._removeClass("ui-autocomplete-loading")}.bind(this)},__response:function(t){t=t&&this._normalize(t),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this._off(this.document,"mousedown"),this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(t){return t.length&&t[0].label&&t[0].value?t:x.map(t,function(t){return"string"==typeof t?{label:t,value:t}:x.extend({},t,{label:t.label||t.value,value:t.value||t.label})})},_suggest:function(t){var e=this.menu.element.empty();this._renderMenu(e,t),this.isNewMenu=!0,this.menu.refresh(),e.show(),this._resizeMenu(),e.position(x.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next(),this._on(this.document,{mousedown:"_closeOnClickOutside"})},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(i,t){var s=this;x.each(t,function(t,e){s._renderItemData(i,e)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(t,e){return x("<li>").append(x("<div>").text(e.label)).appendTo(t)},_move:function(t,e){if(this.menu.element.is(":visible"))return this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),void this.menu.blur()):void this.menu[t](e);this.search(null,e)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){this.isMultiLine&&!this.menu.element.is(":visible")||(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),x.extend(x.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(t,e){var i=new RegExp(x.ui.autocomplete.escapeRegex(e),"i");return x.grep(t,function(t){return i.test(t.label||t.value||t)})}}),x.widget("ui.autocomplete",x.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(1<t?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,clearTimeout(this.liveRegionTimer),this.liveRegionTimer=this._delay(function(){this.liveRegion.html(x("<div>").text(e))},100))}});x.ui.autocomplete});
\ No newline at end of file
diff --git a/java/doc/jquery/jszip-utils/dist/jszip-utils-ie.js b/java/doc/jquery/jszip-utils/dist/jszip-utils-ie.js
new file mode 100644 (file)
index 0000000..a74cc70
--- /dev/null
@@ -0,0 +1,56 @@
+/*!
+
+JSZipUtils - A collection of cross-browser utilities to go along with JSZip.
+<http://stuk.github.io/jszip-utils>
+
+(c) 2014 Stuart Knightley, David Duponchel
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown.
+
+*/
+;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/* jshint evil: true, newcap: false */
+/* global IEBinaryToArray_ByteStr, IEBinaryToArray_ByteStr_Last */
+"use strict";
+
+// Adapted from http://stackoverflow.com/questions/1095102/how-do-i-load-binary-image-data-using-javascript-and-xmlhttprequest
+var IEBinaryToArray_ByteStr_Script =
+    "<!-- IEBinaryToArray_ByteStr -->\r\n"+
+    "<script type='text/vbscript'>\r\n"+
+    "Function IEBinaryToArray_ByteStr(Binary)\r\n"+
+    "   IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+
+    "End Function\r\n"+
+    "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+
+    "   Dim lastIndex\r\n"+
+    "   lastIndex = LenB(Binary)\r\n"+
+    "   if lastIndex mod 2 Then\r\n"+
+    "       IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+
+    "   Else\r\n"+
+    "       IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+
+    "   End If\r\n"+
+    "End Function\r\n"+
+    "</script>\r\n";
+
+// inject VBScript
+document.write(IEBinaryToArray_ByteStr_Script);
+
+global.JSZipUtils._getBinaryFromXHR = function (xhr) {
+    var binary = xhr.responseBody;
+    var byteMapping = {};
+    for ( var i = 0; i < 256; i++ ) {
+        for ( var j = 0; j < 256; j++ ) {
+            byteMapping[ String.fromCharCode( i + (j << 8) ) ] =
+                String.fromCharCode(i) + String.fromCharCode(j);
+        }
+    }
+    var rawBytes = IEBinaryToArray_ByteStr(binary);
+    var lastChr = IEBinaryToArray_ByteStr_Last(binary);
+    return rawBytes.replace(/[\s\S]/g, function( match ) {
+        return byteMapping[match];
+    }) + lastChr;
+};
+
+// enforcing Stuk's coding style
+// vim: set shiftwidth=4 softtabstop=4:
+
+},{}]},{},[1])
+;
diff --git a/java/doc/jquery/jszip-utils/dist/jszip-utils-ie.min.js b/java/doc/jquery/jszip-utils/dist/jszip-utils-ie.min.js
new file mode 100644 (file)
index 0000000..93d8bc8
--- /dev/null
@@ -0,0 +1,10 @@
+/*!
+
+JSZipUtils - A collection of cross-browser utilities to go along with JSZip.
+<http://stuk.github.io/jszip-utils>
+
+(c) 2014 Stuart Knightley, David Duponchel
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown.
+
+*/
+!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(){var a="undefined"!=typeof self?self:"undefined"!=typeof window?window:{},b="<!-- IEBinaryToArray_ByteStr -->\r\n<script type='text/vbscript'>\r\nFunction IEBinaryToArray_ByteStr(Binary)\r\n   IEBinaryToArray_ByteStr = CStr(Binary)\r\nEnd Function\r\nFunction IEBinaryToArray_ByteStr_Last(Binary)\r\n   Dim lastIndex\r\n   lastIndex = LenB(Binary)\r\n   if lastIndex mod 2 Then\r\n       IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n   Else\r\n       IEBinaryToArray_ByteStr_Last = \"\"\r\n   End If\r\nEnd Function\r\n</script>\r\n";document.write(b),a.JSZipUtils._getBinaryFromXHR=function(a){for(var b=a.responseBody,c={},d=0;256>d;d++)for(var e=0;256>e;e++)c[String.fromCharCode(d+(e<<8))]=String.fromCharCode(d)+String.fromCharCode(e);var f=IEBinaryToArray_ByteStr(b),g=IEBinaryToArray_ByteStr_Last(b);return f.replace(/[\s\S]/g,function(a){return c[a]})+g}},{}]},{},[1]);
diff --git a/java/doc/jquery/jszip-utils/dist/jszip-utils.js b/java/doc/jquery/jszip-utils/dist/jszip-utils.js
new file mode 100644 (file)
index 0000000..775895e
--- /dev/null
@@ -0,0 +1,118 @@
+/*!
+
+JSZipUtils - A collection of cross-browser utilities to go along with JSZip.
+<http://stuk.github.io/jszip-utils>
+
+(c) 2014 Stuart Knightley, David Duponchel
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown.
+
+*/
+!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.JSZipUtils=e():"undefined"!=typeof global?global.JSZipUtils=e():"undefined"!=typeof self&&(self.JSZipUtils=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+'use strict';
+
+var JSZipUtils = {};
+// just use the responseText with xhr1, response with xhr2.
+// The transformation doesn't throw away high-order byte (with responseText)
+// because JSZip handles that case. If not used with JSZip, you may need to
+// do it, see https://developer.mozilla.org/En/Using_XMLHttpRequest#Handling_binary_data
+JSZipUtils._getBinaryFromXHR = function (xhr) {
+    // for xhr.responseText, the 0xFF mask is applied by JSZip
+    return xhr.response || xhr.responseText;
+};
+
+// taken from jQuery
+function createStandardXHR() {
+    try {
+        return new window.XMLHttpRequest();
+    } catch( e ) {}
+}
+
+function createActiveXHR() {
+    try {
+        return new window.ActiveXObject("Microsoft.XMLHTTP");
+    } catch( e ) {}
+}
+
+// Create the request object
+var createXHR = window.ActiveXObject ?
+    /* Microsoft failed to properly
+     * implement the XMLHttpRequest in IE7 (can't request local files),
+     * so we use the ActiveXObject when it is available
+     * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+     * we need a fallback.
+     */
+    function() {
+    return createStandardXHR() || createActiveXHR();
+} :
+    // For all other browsers, use the standard XMLHttpRequest object
+    createStandardXHR;
+
+
+
+JSZipUtils.getBinaryContent = function(path, callback) {
+    /*
+     * Here is the tricky part : getting the data.
+     * In firefox/chrome/opera/... setting the mimeType to 'text/plain; charset=x-user-defined'
+     * is enough, the result is in the standard xhr.responseText.
+     * cf https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Receiving_binary_data_in_older_browsers
+     * In IE <= 9, we must use (the IE only) attribute responseBody
+     * (for binary data, its content is different from responseText).
+     * In IE 10, the 'charset=x-user-defined' trick doesn't work, only the
+     * responseType will work :
+     * http://msdn.microsoft.com/en-us/library/ie/hh673569%28v=vs.85%29.aspx#Binary_Object_upload_and_download
+     *
+     * I'd like to use jQuery to avoid this XHR madness, but it doesn't support
+     * the responseType attribute : http://bugs.jquery.com/ticket/11461
+     */
+    try {
+
+        var xhr = createXHR();
+
+        xhr.open('GET', path, true);
+
+        // recent browsers
+        if ("responseType" in xhr) {
+            xhr.responseType = "arraybuffer";
+        }
+
+        // older browser
+        if(xhr.overrideMimeType) {
+            xhr.overrideMimeType("text/plain; charset=x-user-defined");
+        }
+
+        xhr.onreadystatechange = function(evt) {
+            var file, err;
+            // use `xhr` and not `this`... thanks IE
+            if (xhr.readyState === 4) {
+                if (xhr.status === 200 || xhr.status === 0) {
+                    file = null;
+                    err = null;
+                    try {
+                        file = JSZipUtils._getBinaryFromXHR(xhr);
+                    } catch(e) {
+                        err = new Error(e);
+                    }
+                    callback(err, file);
+                } else {
+                    callback(new Error("Ajax error for " + path + " : " + this.status + " " + this.statusText), null);
+                }
+            }
+        };
+
+        xhr.send();
+
+    } catch (e) {
+        callback(new Error(e), null);
+    }
+};
+
+// export
+module.exports = JSZipUtils;
+
+// enforcing Stuk's coding style
+// vim: set shiftwidth=4 softtabstop=4:
+
+},{}]},{},[1])
+(1)
+});
+;
diff --git a/java/doc/jquery/jszip-utils/dist/jszip-utils.min.js b/java/doc/jquery/jszip-utils/dist/jszip-utils.min.js
new file mode 100644 (file)
index 0000000..78c7f5e
--- /dev/null
@@ -0,0 +1,10 @@
+/*!
+
+JSZipUtils - A collection of cross-browser utilities to go along with JSZip.
+<http://stuk.github.io/jszip-utils>
+
+(c) 2014 Stuart Knightley, David Duponchel
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip-utils/master/LICENSE.markdown.
+
+*/
+!function(a){"object"==typeof exports?module.exports=a():"function"==typeof define&&define.amd?define(a):"undefined"!=typeof window?window.JSZipUtils=a():"undefined"!=typeof global?global.JSZipUtils=a():"undefined"!=typeof self&&(self.JSZipUtils=a())}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){"use strict";function c(){try{return new window.XMLHttpRequest}catch(a){}}function d(){try{return new window.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}}var e={};e._getBinaryFromXHR=function(a){return a.response||a.responseText};var f=window.ActiveXObject?function(){return c()||d()}:c;e.getBinaryContent=function(a,b){try{var c=f();c.open("GET",a,!0),"responseType"in c&&(c.responseType="arraybuffer"),c.overrideMimeType&&c.overrideMimeType("text/plain; charset=x-user-defined"),c.onreadystatechange=function(){var d,f;if(4===c.readyState)if(200===c.status||0===c.status){d=null,f=null;try{d=e._getBinaryFromXHR(c)}catch(g){f=new Error(g)}b(f,d)}else b(new Error("Ajax error for "+a+" : "+this.status+" "+this.statusText),null)},c.send()}catch(d){b(new Error(d),null)}},b.exports=e},{}]},{},[1])(1)});
diff --git a/java/doc/jquery/jszip/dist/jszip.js b/java/doc/jquery/jszip/dist/jszip.js
new file mode 100644 (file)
index 0000000..9f0ffc1
--- /dev/null
@@ -0,0 +1,11370 @@
+/*!
+
+JSZip v3.7.1 - A JavaScript class for generating and reading zip files
+<http://stuartk.com/jszip>
+
+(c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.
+
+JSZip uses the library pako released under the MIT license :
+https://github.com/nodeca/pako/blob/master/LICENSE
+*/
+
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JSZip = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+'use strict';
+var utils = require('./utils');
+var support = require('./support');
+// private property
+var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+
+// public method for encoding
+exports.encode = function(input) {
+    var output = [];
+    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+    var i = 0, len = input.length, remainingBytes = len;
+
+    var isArray = utils.getTypeOf(input) !== "string";
+    while (i < input.length) {
+        remainingBytes = len - i;
+
+        if (!isArray) {
+            chr1 = input.charCodeAt(i++);
+            chr2 = i < len ? input.charCodeAt(i++) : 0;
+            chr3 = i < len ? input.charCodeAt(i++) : 0;
+        } else {
+            chr1 = input[i++];
+            chr2 = i < len ? input[i++] : 0;
+            chr3 = i < len ? input[i++] : 0;
+        }
+
+        enc1 = chr1 >> 2;
+        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+        enc3 = remainingBytes > 1 ? (((chr2 & 15) << 2) | (chr3 >> 6)) : 64;
+        enc4 = remainingBytes > 2 ? (chr3 & 63) : 64;
+
+        output.push(_keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4));
+
+    }
+
+    return output.join("");
+};
+
+// public method for decoding
+exports.decode = function(input) {
+    var chr1, chr2, chr3;
+    var enc1, enc2, enc3, enc4;
+    var i = 0, resultIndex = 0;
+
+    var dataUrlPrefix = "data:";
+
+    if (input.substr(0, dataUrlPrefix.length) === dataUrlPrefix) {
+        // This is a common error: people give a data url
+        // (data:image/png;base64,iVBOR...) with a {base64: true} and
+        // wonders why things don't work.
+        // We can detect that the string input looks like a data url but we
+        // *can't* be sure it is one: removing everything up to the comma would
+        // be too dangerous.
+        throw new Error("Invalid base64 input, it looks like a data url.");
+    }
+
+    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+    var totalLength = input.length * 3 / 4;
+    if(input.charAt(input.length - 1) === _keyStr.charAt(64)) {
+        totalLength--;
+    }
+    if(input.charAt(input.length - 2) === _keyStr.charAt(64)) {
+        totalLength--;
+    }
+    if (totalLength % 1 !== 0) {
+        // totalLength is not an integer, the length does not match a valid
+        // base64 content. That can happen if:
+        // - the input is not a base64 content
+        // - the input is *almost* a base64 content, with a extra chars at the
+        //   beginning or at the end
+        // - the input uses a base64 variant (base64url for example)
+        throw new Error("Invalid base64 input, bad content length.");
+    }
+    var output;
+    if (support.uint8array) {
+        output = new Uint8Array(totalLength|0);
+    } else {
+        output = new Array(totalLength|0);
+    }
+
+    while (i < input.length) {
+
+        enc1 = _keyStr.indexOf(input.charAt(i++));
+        enc2 = _keyStr.indexOf(input.charAt(i++));
+        enc3 = _keyStr.indexOf(input.charAt(i++));
+        enc4 = _keyStr.indexOf(input.charAt(i++));
+
+        chr1 = (enc1 << 2) | (enc2 >> 4);
+        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+        chr3 = ((enc3 & 3) << 6) | enc4;
+
+        output[resultIndex++] = chr1;
+
+        if (enc3 !== 64) {
+            output[resultIndex++] = chr2;
+        }
+        if (enc4 !== 64) {
+            output[resultIndex++] = chr3;
+        }
+
+    }
+
+    return output;
+};
+
+},{"./support":30,"./utils":32}],2:[function(require,module,exports){
+'use strict';
+
+var external = require("./external");
+var DataWorker = require('./stream/DataWorker');
+var Crc32Probe = require('./stream/Crc32Probe');
+var DataLengthProbe = require('./stream/DataLengthProbe');
+
+/**
+ * Represent a compressed object, with everything needed to decompress it.
+ * @constructor
+ * @param {number} compressedSize the size of the data compressed.
+ * @param {number} uncompressedSize the size of the data after decompression.
+ * @param {number} crc32 the crc32 of the decompressed file.
+ * @param {object} compression the type of compression, see lib/compressions.js.
+ * @param {String|ArrayBuffer|Uint8Array|Buffer} data the compressed data.
+ */
+function CompressedObject(compressedSize, uncompressedSize, crc32, compression, data) {
+    this.compressedSize = compressedSize;
+    this.uncompressedSize = uncompressedSize;
+    this.crc32 = crc32;
+    this.compression = compression;
+    this.compressedContent = data;
+}
+
+CompressedObject.prototype = {
+    /**
+     * Create a worker to get the uncompressed content.
+     * @return {GenericWorker} the worker.
+     */
+    getContentWorker: function () {
+        var worker = new DataWorker(external.Promise.resolve(this.compressedContent))
+            .pipe(this.compression.uncompressWorker())
+            .pipe(new DataLengthProbe("data_length"));
+
+        var that = this;
+        worker.on("end", function () {
+            if (this.streamInfo['data_length'] !== that.uncompressedSize) {
+                throw new Error("Bug : uncompressed data size mismatch");
+            }
+        });
+        return worker;
+    },
+    /**
+     * Create a worker to get the compressed content.
+     * @return {GenericWorker} the worker.
+     */
+    getCompressedWorker: function () {
+        return new DataWorker(external.Promise.resolve(this.compressedContent))
+            .withStreamInfo("compressedSize", this.compressedSize)
+            .withStreamInfo("uncompressedSize", this.uncompressedSize)
+            .withStreamInfo("crc32", this.crc32)
+            .withStreamInfo("compression", this.compression)
+            ;
+    }
+};
+
+/**
+ * Chain the given worker with other workers to compress the content with the
+ * given compression.
+ * @param {GenericWorker} uncompressedWorker the worker to pipe.
+ * @param {Object} compression the compression object.
+ * @param {Object} compressionOptions the options to use when compressing.
+ * @return {GenericWorker} the new worker compressing the content.
+ */
+CompressedObject.createWorkerFrom = function (uncompressedWorker, compression, compressionOptions) {
+    return uncompressedWorker
+        .pipe(new Crc32Probe())
+        .pipe(new DataLengthProbe("uncompressedSize"))
+        .pipe(compression.compressWorker(compressionOptions))
+        .pipe(new DataLengthProbe("compressedSize"))
+        .withStreamInfo("compression", compression);
+};
+
+module.exports = CompressedObject;
+
+},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(require,module,exports){
+'use strict';
+
+var GenericWorker = require("./stream/GenericWorker");
+
+exports.STORE = {
+    magic: "\x00\x00",
+    compressWorker : function (compressionOptions) {
+        return new GenericWorker("STORE compression");
+    },
+    uncompressWorker : function () {
+        return new GenericWorker("STORE decompression");
+    }
+};
+exports.DEFLATE = require('./flate');
+
+},{"./flate":7,"./stream/GenericWorker":28}],4:[function(require,module,exports){
+'use strict';
+
+var utils = require('./utils');
+
+/**
+ * The following functions come from pako, from pako/lib/zlib/crc32.js
+ * released under the MIT license, see pako https://github.com/nodeca/pako/
+ */
+
+// Use ordinary array, since untyped makes no boost here
+function makeTable() {
+    var c, table = [];
+
+    for(var n =0; n < 256; n++){
+        c = n;
+        for(var k =0; k < 8; k++){
+            c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
+        }
+        table[n] = c;
+    }
+
+    return table;
+}
+
+// Create table on load. Just 255 signed longs. Not a problem.
+var crcTable = makeTable();
+
+
+function crc32(crc, buf, len, pos) {
+    var t = crcTable, end = pos + len;
+
+    crc = crc ^ (-1);
+
+    for (var i = pos; i < end; i++ ) {
+        crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
+    }
+
+    return (crc ^ (-1)); // >>> 0;
+}
+
+// That's all for the pako functions.
+
+/**
+ * Compute the crc32 of a string.
+ * This is almost the same as the function crc32, but for strings. Using the
+ * same function for the two use cases leads to horrible performances.
+ * @param {Number} crc the starting value of the crc.
+ * @param {String} str the string to use.
+ * @param {Number} len the length of the string.
+ * @param {Number} pos the starting position for the crc32 computation.
+ * @return {Number} the computed crc32.
+ */
+function crc32str(crc, str, len, pos) {
+    var t = crcTable, end = pos + len;
+
+    crc = crc ^ (-1);
+
+    for (var i = pos; i < end; i++ ) {
+        crc = (crc >>> 8) ^ t[(crc ^ str.charCodeAt(i)) & 0xFF];
+    }
+
+    return (crc ^ (-1)); // >>> 0;
+}
+
+module.exports = function crc32wrapper(input, crc) {
+    if (typeof input === "undefined" || !input.length) {
+        return 0;
+    }
+
+    var isArray = utils.getTypeOf(input) !== "string";
+
+    if(isArray) {
+        return crc32(crc|0, input, input.length, 0);
+    } else {
+        return crc32str(crc|0, input, input.length, 0);
+    }
+};
+
+},{"./utils":32}],5:[function(require,module,exports){
+'use strict';
+exports.base64 = false;
+exports.binary = false;
+exports.dir = false;
+exports.createFolders = true;
+exports.date = null;
+exports.compression = null;
+exports.compressionOptions = null;
+exports.comment = null;
+exports.unixPermissions = null;
+exports.dosPermissions = null;
+
+},{}],6:[function(require,module,exports){
+/* global Promise */
+'use strict';
+
+// load the global object first:
+// - it should be better integrated in the system (unhandledRejection in node)
+// - the environment may have a custom Promise implementation (see zone.js)
+var ES6Promise = null;
+if (typeof Promise !== "undefined") {
+    ES6Promise = Promise;
+} else {
+    ES6Promise = require("lie");
+}
+
+/**
+ * Let the user use/change some implementations.
+ */
+module.exports = {
+    Promise: ES6Promise
+};
+
+},{"lie":37}],7:[function(require,module,exports){
+'use strict';
+var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined');
+
+var pako = require("pako");
+var utils = require("./utils");
+var GenericWorker = require("./stream/GenericWorker");
+
+var ARRAY_TYPE = USE_TYPEDARRAY ? "uint8array" : "array";
+
+exports.magic = "\x08\x00";
+
+/**
+ * Create a worker that uses pako to inflate/deflate.
+ * @constructor
+ * @param {String} action the name of the pako function to call : either "Deflate" or "Inflate".
+ * @param {Object} options the options to use when (de)compressing.
+ */
+function FlateWorker(action, options) {
+    GenericWorker.call(this, "FlateWorker/" + action);
+
+    this._pako = null;
+    this._pakoAction = action;
+    this._pakoOptions = options;
+    // the `meta` object from the last chunk received
+    // this allow this worker to pass around metadata
+    this.meta = {};
+}
+
+utils.inherits(FlateWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+FlateWorker.prototype.processChunk = function (chunk) {
+    this.meta = chunk.meta;
+    if (this._pako === null) {
+        this._createPako();
+    }
+    this._pako.push(utils.transformTo(ARRAY_TYPE, chunk.data), false);
+};
+
+/**
+ * @see GenericWorker.flush
+ */
+FlateWorker.prototype.flush = function () {
+    GenericWorker.prototype.flush.call(this);
+    if (this._pako === null) {
+        this._createPako();
+    }
+    this._pako.push([], true);
+};
+/**
+ * @see GenericWorker.cleanUp
+ */
+FlateWorker.prototype.cleanUp = function () {
+    GenericWorker.prototype.cleanUp.call(this);
+    this._pako = null;
+};
+
+/**
+ * Create the _pako object.
+ * TODO: lazy-loading this object isn't the best solution but it's the
+ * quickest. The best solution is to lazy-load the worker list. See also the
+ * issue #446.
+ */
+FlateWorker.prototype._createPako = function () {
+    this._pako = new pako[this._pakoAction]({
+        raw: true,
+        level: this._pakoOptions.level || -1 // default compression
+    });
+    var self = this;
+    this._pako.onData = function(data) {
+        self.push({
+            data : data,
+            meta : self.meta
+        });
+    };
+};
+
+exports.compressWorker = function (compressionOptions) {
+    return new FlateWorker("Deflate", compressionOptions);
+};
+exports.uncompressWorker = function () {
+    return new FlateWorker("Inflate", {});
+};
+
+},{"./stream/GenericWorker":28,"./utils":32,"pako":38}],8:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var GenericWorker = require('../stream/GenericWorker');
+var utf8 = require('../utf8');
+var crc32 = require('../crc32');
+var signature = require('../signature');
+
+/**
+ * Transform an integer into a string in hexadecimal.
+ * @private
+ * @param {number} dec the number to convert.
+ * @param {number} bytes the number of bytes to generate.
+ * @returns {string} the result.
+ */
+var decToHex = function(dec, bytes) {
+    var hex = "", i;
+    for (i = 0; i < bytes; i++) {
+        hex += String.fromCharCode(dec & 0xff);
+        dec = dec >>> 8;
+    }
+    return hex;
+};
+
+/**
+ * Generate the UNIX part of the external file attributes.
+ * @param {Object} unixPermissions the unix permissions or null.
+ * @param {Boolean} isDir true if the entry is a directory, false otherwise.
+ * @return {Number} a 32 bit integer.
+ *
+ * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute :
+ *
+ * TTTTsstrwxrwxrwx0000000000ADVSHR
+ * ^^^^____________________________ file type, see zipinfo.c (UNX_*)
+ *     ^^^_________________________ setuid, setgid, sticky
+ *        ^^^^^^^^^________________ permissions
+ *                 ^^^^^^^^^^______ not used ?
+ *                           ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only
+ */
+var generateUnixExternalFileAttr = function (unixPermissions, isDir) {
+
+    var result = unixPermissions;
+    if (!unixPermissions) {
+        // I can't use octal values in strict mode, hence the hexa.
+        //  040775 => 0x41fd
+        // 0100664 => 0x81b4
+        result = isDir ? 0x41fd : 0x81b4;
+    }
+    return (result & 0xFFFF) << 16;
+};
+
+/**
+ * Generate the DOS part of the external file attributes.
+ * @param {Object} dosPermissions the dos permissions or null.
+ * @param {Boolean} isDir true if the entry is a directory, false otherwise.
+ * @return {Number} a 32 bit integer.
+ *
+ * Bit 0     Read-Only
+ * Bit 1     Hidden
+ * Bit 2     System
+ * Bit 3     Volume Label
+ * Bit 4     Directory
+ * Bit 5     Archive
+ */
+var generateDosExternalFileAttr = function (dosPermissions, isDir) {
+
+    // the dir flag is already set for compatibility
+    return (dosPermissions || 0)  & 0x3F;
+};
+
+/**
+ * Generate the various parts used in the construction of the final zip file.
+ * @param {Object} streamInfo the hash with information about the compressed file.
+ * @param {Boolean} streamedContent is the content streamed ?
+ * @param {Boolean} streamingEnded is the stream finished ?
+ * @param {number} offset the current offset from the start of the zip file.
+ * @param {String} platform let's pretend we are this platform (change platform dependents fields)
+ * @param {Function} encodeFileName the function to encode the file name / comment.
+ * @return {Object} the zip parts.
+ */
+var generateZipParts = function(streamInfo, streamedContent, streamingEnded, offset, platform, encodeFileName) {
+    var file = streamInfo['file'],
+    compression = streamInfo['compression'],
+    useCustomEncoding = encodeFileName !== utf8.utf8encode,
+    encodedFileName = utils.transformTo("string", encodeFileName(file.name)),
+    utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)),
+    comment = file.comment,
+    encodedComment = utils.transformTo("string", encodeFileName(comment)),
+    utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)),
+    useUTF8ForFileName = utfEncodedFileName.length !== file.name.length,
+    useUTF8ForComment = utfEncodedComment.length !== comment.length,
+    dosTime,
+    dosDate,
+    extraFields = "",
+    unicodePathExtraField = "",
+    unicodeCommentExtraField = "",
+    dir = file.dir,
+    date = file.date;
+
+
+    var dataInfo = {
+        crc32 : 0,
+        compressedSize : 0,
+        uncompressedSize : 0
+    };
+
+    // if the content is streamed, the sizes/crc32 are only available AFTER
+    // the end of the stream.
+    if (!streamedContent || streamingEnded) {
+        dataInfo.crc32 = streamInfo['crc32'];
+        dataInfo.compressedSize = streamInfo['compressedSize'];
+        dataInfo.uncompressedSize = streamInfo['uncompressedSize'];
+    }
+
+    var bitflag = 0;
+    if (streamedContent) {
+        // Bit 3: the sizes/crc32 are set to zero in the local header.
+        // The correct values are put in the data descriptor immediately
+        // following the compressed data.
+        bitflag |= 0x0008;
+    }
+    if (!useCustomEncoding && (useUTF8ForFileName || useUTF8ForComment)) {
+        // Bit 11: Language encoding flag (EFS).
+        bitflag |= 0x0800;
+    }
+
+
+    var extFileAttr = 0;
+    var versionMadeBy = 0;
+    if (dir) {
+        // dos or unix, we set the dos dir flag
+        extFileAttr |= 0x00010;
+    }
+    if(platform === "UNIX") {
+        versionMadeBy = 0x031E; // UNIX, version 3.0
+        extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir);
+    } else { // DOS or other, fallback to DOS
+        versionMadeBy = 0x0014; // DOS, version 2.0
+        extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir);
+    }
+
+    // date
+    // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
+    // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
+    // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
+
+    dosTime = date.getUTCHours();
+    dosTime = dosTime << 6;
+    dosTime = dosTime | date.getUTCMinutes();
+    dosTime = dosTime << 5;
+    dosTime = dosTime | date.getUTCSeconds() / 2;
+
+    dosDate = date.getUTCFullYear() - 1980;
+    dosDate = dosDate << 4;
+    dosDate = dosDate | (date.getUTCMonth() + 1);
+    dosDate = dosDate << 5;
+    dosDate = dosDate | date.getUTCDate();
+
+    if (useUTF8ForFileName) {
+        // set the unicode path extra field. unzip needs at least one extra
+        // field to correctly handle unicode path, so using the path is as good
+        // as any other information. This could improve the situation with
+        // other archive managers too.
+        // This field is usually used without the utf8 flag, with a non
+        // unicode path in the header (winrar, winzip). This helps (a bit)
+        // with the messy Windows' default compressed folders feature but
+        // breaks on p7zip which doesn't seek the unicode path extra field.
+        // So for now, UTF-8 everywhere !
+        unicodePathExtraField =
+            // Version
+            decToHex(1, 1) +
+            // NameCRC32
+            decToHex(crc32(encodedFileName), 4) +
+            // UnicodeName
+            utfEncodedFileName;
+
+        extraFields +=
+            // Info-ZIP Unicode Path Extra Field
+            "\x75\x70" +
+            // size
+            decToHex(unicodePathExtraField.length, 2) +
+            // content
+            unicodePathExtraField;
+    }
+
+    if(useUTF8ForComment) {
+
+        unicodeCommentExtraField =
+            // Version
+            decToHex(1, 1) +
+            // CommentCRC32
+            decToHex(crc32(encodedComment), 4) +
+            // UnicodeName
+            utfEncodedComment;
+
+        extraFields +=
+            // Info-ZIP Unicode Path Extra Field
+            "\x75\x63" +
+            // size
+            decToHex(unicodeCommentExtraField.length, 2) +
+            // content
+            unicodeCommentExtraField;
+    }
+
+    var header = "";
+
+    // version needed to extract
+    header += "\x0A\x00";
+    // general purpose bit flag
+    header += decToHex(bitflag, 2);
+    // compression method
+    header += compression.magic;
+    // last mod file time
+    header += decToHex(dosTime, 2);
+    // last mod file date
+    header += decToHex(dosDate, 2);
+    // crc-32
+    header += decToHex(dataInfo.crc32, 4);
+    // compressed size
+    header += decToHex(dataInfo.compressedSize, 4);
+    // uncompressed size
+    header += decToHex(dataInfo.uncompressedSize, 4);
+    // file name length
+    header += decToHex(encodedFileName.length, 2);
+    // extra field length
+    header += decToHex(extraFields.length, 2);
+
+
+    var fileRecord = signature.LOCAL_FILE_HEADER + header + encodedFileName + extraFields;
+
+    var dirRecord = signature.CENTRAL_FILE_HEADER +
+        // version made by (00: DOS)
+        decToHex(versionMadeBy, 2) +
+        // file header (common to file and central directory)
+        header +
+        // file comment length
+        decToHex(encodedComment.length, 2) +
+        // disk number start
+        "\x00\x00" +
+        // internal file attributes TODO
+        "\x00\x00" +
+        // external file attributes
+        decToHex(extFileAttr, 4) +
+        // relative offset of local header
+        decToHex(offset, 4) +
+        // file name
+        encodedFileName +
+        // extra field
+        extraFields +
+        // file comment
+        encodedComment;
+
+    return {
+        fileRecord: fileRecord,
+        dirRecord: dirRecord
+    };
+};
+
+/**
+ * Generate the EOCD record.
+ * @param {Number} entriesCount the number of entries in the zip file.
+ * @param {Number} centralDirLength the length (in bytes) of the central dir.
+ * @param {Number} localDirLength the length (in bytes) of the local dir.
+ * @param {String} comment the zip file comment as a binary string.
+ * @param {Function} encodeFileName the function to encode the comment.
+ * @return {String} the EOCD record.
+ */
+var generateCentralDirectoryEnd = function (entriesCount, centralDirLength, localDirLength, comment, encodeFileName) {
+    var dirEnd = "";
+    var encodedComment = utils.transformTo("string", encodeFileName(comment));
+
+    // end of central dir signature
+    dirEnd = signature.CENTRAL_DIRECTORY_END +
+        // number of this disk
+        "\x00\x00" +
+        // number of the disk with the start of the central directory
+        "\x00\x00" +
+        // total number of entries in the central directory on this disk
+        decToHex(entriesCount, 2) +
+        // total number of entries in the central directory
+        decToHex(entriesCount, 2) +
+        // size of the central directory   4 bytes
+        decToHex(centralDirLength, 4) +
+        // offset of start of central directory with respect to the starting disk number
+        decToHex(localDirLength, 4) +
+        // .ZIP file comment length
+        decToHex(encodedComment.length, 2) +
+        // .ZIP file comment
+        encodedComment;
+
+    return dirEnd;
+};
+
+/**
+ * Generate data descriptors for a file entry.
+ * @param {Object} streamInfo the hash generated by a worker, containing information
+ * on the file entry.
+ * @return {String} the data descriptors.
+ */
+var generateDataDescriptors = function (streamInfo) {
+    var descriptor = "";
+    descriptor = signature.DATA_DESCRIPTOR +
+        // crc-32                          4 bytes
+        decToHex(streamInfo['crc32'], 4) +
+        // compressed size                 4 bytes
+        decToHex(streamInfo['compressedSize'], 4) +
+        // uncompressed size               4 bytes
+        decToHex(streamInfo['uncompressedSize'], 4);
+
+    return descriptor;
+};
+
+
+/**
+ * A worker to concatenate other workers to create a zip file.
+ * @param {Boolean} streamFiles `true` to stream the content of the files,
+ * `false` to accumulate it.
+ * @param {String} comment the comment to use.
+ * @param {String} platform the platform to use, "UNIX" or "DOS".
+ * @param {Function} encodeFileName the function to encode file names and comments.
+ */
+function ZipFileWorker(streamFiles, comment, platform, encodeFileName) {
+    GenericWorker.call(this, "ZipFileWorker");
+    // The number of bytes written so far. This doesn't count accumulated chunks.
+    this.bytesWritten = 0;
+    // The comment of the zip file
+    this.zipComment = comment;
+    // The platform "generating" the zip file.
+    this.zipPlatform = platform;
+    // the function to encode file names and comments.
+    this.encodeFileName = encodeFileName;
+    // Should we stream the content of the files ?
+    this.streamFiles = streamFiles;
+    // If `streamFiles` is false, we will need to accumulate the content of the
+    // files to calculate sizes / crc32 (and write them *before* the content).
+    // This boolean indicates if we are accumulating chunks (it will change a lot
+    // during the lifetime of this worker).
+    this.accumulate = false;
+    // The buffer receiving chunks when accumulating content.
+    this.contentBuffer = [];
+    // The list of generated directory records.
+    this.dirRecords = [];
+    // The offset (in bytes) from the beginning of the zip file for the current source.
+    this.currentSourceOffset = 0;
+    // The total number of entries in this zip file.
+    this.entriesCount = 0;
+    // the name of the file currently being added, null when handling the end of the zip file.
+    // Used for the emitted metadata.
+    this.currentFile = null;
+
+
+
+    this._sources = [];
+}
+utils.inherits(ZipFileWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.push
+ */
+ZipFileWorker.prototype.push = function (chunk) {
+
+    var currentFilePercent = chunk.meta.percent || 0;
+    var entriesCount = this.entriesCount;
+    var remainingFiles = this._sources.length;
+
+    if(this.accumulate) {
+        this.contentBuffer.push(chunk);
+    } else {
+        this.bytesWritten += chunk.data.length;
+
+        GenericWorker.prototype.push.call(this, {
+            data : chunk.data,
+            meta : {
+                currentFile : this.currentFile,
+                percent : entriesCount ? (currentFilePercent + 100 * (entriesCount - remainingFiles - 1)) / entriesCount : 100
+            }
+        });
+    }
+};
+
+/**
+ * The worker started a new source (an other worker).
+ * @param {Object} streamInfo the streamInfo object from the new source.
+ */
+ZipFileWorker.prototype.openedSource = function (streamInfo) {
+    this.currentSourceOffset = this.bytesWritten;
+    this.currentFile = streamInfo['file'].name;
+
+    var streamedContent = this.streamFiles && !streamInfo['file'].dir;
+
+    // don't stream folders (because they don't have any content)
+    if(streamedContent) {
+        var record = generateZipParts(streamInfo, streamedContent, false, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
+        this.push({
+            data : record.fileRecord,
+            meta : {percent:0}
+        });
+    } else {
+        // we need to wait for the whole file before pushing anything
+        this.accumulate = true;
+    }
+};
+
+/**
+ * The worker finished a source (an other worker).
+ * @param {Object} streamInfo the streamInfo object from the finished source.
+ */
+ZipFileWorker.prototype.closedSource = function (streamInfo) {
+    this.accumulate = false;
+    var streamedContent = this.streamFiles && !streamInfo['file'].dir;
+    var record = generateZipParts(streamInfo, streamedContent, true, this.currentSourceOffset, this.zipPlatform, this.encodeFileName);
+
+    this.dirRecords.push(record.dirRecord);
+    if(streamedContent) {
+        // after the streamed file, we put data descriptors
+        this.push({
+            data : generateDataDescriptors(streamInfo),
+            meta : {percent:100}
+        });
+    } else {
+        // the content wasn't streamed, we need to push everything now
+        // first the file record, then the content
+        this.push({
+            data : record.fileRecord,
+            meta : {percent:0}
+        });
+        while(this.contentBuffer.length) {
+            this.push(this.contentBuffer.shift());
+        }
+    }
+    this.currentFile = null;
+};
+
+/**
+ * @see GenericWorker.flush
+ */
+ZipFileWorker.prototype.flush = function () {
+
+    var localDirLength = this.bytesWritten;
+    for(var i = 0; i < this.dirRecords.length; i++) {
+        this.push({
+            data : this.dirRecords[i],
+            meta : {percent:100}
+        });
+    }
+    var centralDirLength = this.bytesWritten - localDirLength;
+
+    var dirEnd = generateCentralDirectoryEnd(this.dirRecords.length, centralDirLength, localDirLength, this.zipComment, this.encodeFileName);
+
+    this.push({
+        data : dirEnd,
+        meta : {percent:100}
+    });
+};
+
+/**
+ * Prepare the next source to be read.
+ */
+ZipFileWorker.prototype.prepareNextSource = function () {
+    this.previous = this._sources.shift();
+    this.openedSource(this.previous.streamInfo);
+    if (this.isPaused) {
+        this.previous.pause();
+    } else {
+        this.previous.resume();
+    }
+};
+
+/**
+ * @see GenericWorker.registerPrevious
+ */
+ZipFileWorker.prototype.registerPrevious = function (previous) {
+    this._sources.push(previous);
+    var self = this;
+
+    previous.on('data', function (chunk) {
+        self.processChunk(chunk);
+    });
+    previous.on('end', function () {
+        self.closedSource(self.previous.streamInfo);
+        if(self._sources.length) {
+            self.prepareNextSource();
+        } else {
+            self.end();
+        }
+    });
+    previous.on('error', function (e) {
+        self.error(e);
+    });
+    return this;
+};
+
+/**
+ * @see GenericWorker.resume
+ */
+ZipFileWorker.prototype.resume = function () {
+    if(!GenericWorker.prototype.resume.call(this)) {
+        return false;
+    }
+
+    if (!this.previous && this._sources.length) {
+        this.prepareNextSource();
+        return true;
+    }
+    if (!this.previous && !this._sources.length && !this.generatedError) {
+        this.end();
+        return true;
+    }
+};
+
+/**
+ * @see GenericWorker.error
+ */
+ZipFileWorker.prototype.error = function (e) {
+    var sources = this._sources;
+    if(!GenericWorker.prototype.error.call(this, e)) {
+        return false;
+    }
+    for(var i = 0; i < sources.length; i++) {
+        try {
+            sources[i].error(e);
+        } catch(e) {
+            // the `error` exploded, nothing to do
+        }
+    }
+    return true;
+};
+
+/**
+ * @see GenericWorker.lock
+ */
+ZipFileWorker.prototype.lock = function () {
+    GenericWorker.prototype.lock.call(this);
+    var sources = this._sources;
+    for(var i = 0; i < sources.length; i++) {
+        sources[i].lock();
+    }
+};
+
+module.exports = ZipFileWorker;
+
+},{"../crc32":4,"../signature":23,"../stream/GenericWorker":28,"../utf8":31,"../utils":32}],9:[function(require,module,exports){
+'use strict';
+
+var compressions = require('../compressions');
+var ZipFileWorker = require('./ZipFileWorker');
+
+/**
+ * Find the compression to use.
+ * @param {String} fileCompression the compression defined at the file level, if any.
+ * @param {String} zipCompression the compression defined at the load() level.
+ * @return {Object} the compression object to use.
+ */
+var getCompression = function (fileCompression, zipCompression) {
+
+    var compressionName = fileCompression || zipCompression;
+    var compression = compressions[compressionName];
+    if (!compression) {
+        throw new Error(compressionName + " is not a valid compression method !");
+    }
+    return compression;
+};
+
+/**
+ * Create a worker to generate a zip file.
+ * @param {JSZip} zip the JSZip instance at the right root level.
+ * @param {Object} options to generate the zip file.
+ * @param {String} comment the comment to use.
+ */
+exports.generateWorker = function (zip, options, comment) {
+
+    var zipFileWorker = new ZipFileWorker(options.streamFiles, comment, options.platform, options.encodeFileName);
+    var entriesCount = 0;
+    try {
+
+        zip.forEach(function (relativePath, file) {
+            entriesCount++;
+            var compression = getCompression(file.options.compression, options.compression);
+            var compressionOptions = file.options.compressionOptions || options.compressionOptions || {};
+            var dir = file.dir, date = file.date;
+
+            file._compressWorker(compression, compressionOptions)
+            .withStreamInfo("file", {
+                name : relativePath,
+                dir : dir,
+                date : date,
+                comment : file.comment || "",
+                unixPermissions : file.unixPermissions,
+                dosPermissions : file.dosPermissions
+            })
+            .pipe(zipFileWorker);
+        });
+        zipFileWorker.entriesCount = entriesCount;
+    } catch (e) {
+        zipFileWorker.error(e);
+    }
+
+    return zipFileWorker;
+};
+
+},{"../compressions":3,"./ZipFileWorker":8}],10:[function(require,module,exports){
+'use strict';
+
+/**
+ * Representation a of zip file in js
+ * @constructor
+ */
+function JSZip() {
+    // if this constructor is used without `new`, it adds `new` before itself:
+    if(!(this instanceof JSZip)) {
+        return new JSZip();
+    }
+
+    if(arguments.length) {
+        throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
+    }
+
+    // object containing the files :
+    // {
+    //   "folder/" : {...},
+    //   "folder/data.txt" : {...}
+    // }
+    // NOTE: we use a null prototype because we do not
+    // want filenames like "toString" coming from a zip file
+    // to overwrite methods and attributes in a normal Object.
+    this.files = Object.create(null);
+
+    this.comment = null;
+
+    // Where we are in the hierarchy
+    this.root = "";
+    this.clone = function() {
+        var newObj = new JSZip();
+        for (var i in this) {
+            if (typeof this[i] !== "function") {
+                newObj[i] = this[i];
+            }
+        }
+        return newObj;
+    };
+}
+JSZip.prototype = require('./object');
+JSZip.prototype.loadAsync = require('./load');
+JSZip.support = require('./support');
+JSZip.defaults = require('./defaults');
+
+// TODO find a better way to handle this version,
+// a require('package.json').version doesn't work with webpack, see #327
+JSZip.version = "3.7.1";
+
+JSZip.loadAsync = function (content, options) {
+    return new JSZip().loadAsync(content, options);
+};
+
+JSZip.external = require("./external");
+module.exports = JSZip;
+
+},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(require,module,exports){
+'use strict';
+var utils = require('./utils');
+var external = require("./external");
+var utf8 = require('./utf8');
+var ZipEntries = require('./zipEntries');
+var Crc32Probe = require('./stream/Crc32Probe');
+var nodejsUtils = require("./nodejsUtils");
+
+/**
+ * Check the CRC32 of an entry.
+ * @param {ZipEntry} zipEntry the zip entry to check.
+ * @return {Promise} the result.
+ */
+function checkEntryCRC32(zipEntry) {
+    return new external.Promise(function (resolve, reject) {
+        var worker = zipEntry.decompressed.getContentWorker().pipe(new Crc32Probe());
+        worker.on("error", function (e) {
+            reject(e);
+        })
+            .on("end", function () {
+                if (worker.streamInfo.crc32 !== zipEntry.decompressed.crc32) {
+                    reject(new Error("Corrupted zip : CRC32 mismatch"));
+                } else {
+                    resolve();
+                }
+            })
+            .resume();
+    });
+}
+
+module.exports = function (data, options) {
+    var zip = this;
+    options = utils.extend(options || {}, {
+        base64: false,
+        checkCRC32: false,
+        optimizedBinaryString: false,
+        createFolders: false,
+        decodeFileName: utf8.utf8decode
+    });
+
+    if (nodejsUtils.isNode && nodejsUtils.isStream(data)) {
+        return external.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file."));
+    }
+
+    return utils.prepareContent("the loaded zip file", data, true, options.optimizedBinaryString, options.base64)
+        .then(function (data) {
+            var zipEntries = new ZipEntries(options);
+            zipEntries.load(data);
+            return zipEntries;
+        }).then(function checkCRC32(zipEntries) {
+            var promises = [external.Promise.resolve(zipEntries)];
+            var files = zipEntries.files;
+            if (options.checkCRC32) {
+                for (var i = 0; i < files.length; i++) {
+                    promises.push(checkEntryCRC32(files[i]));
+                }
+            }
+            return external.Promise.all(promises);
+        }).then(function addFiles(results) {
+            var zipEntries = results.shift();
+            var files = zipEntries.files;
+            for (var i = 0; i < files.length; i++) {
+                var input = files[i];
+                zip.file(input.fileNameStr, input.decompressed, {
+                    binary: true,
+                    optimizedBinaryString: true,
+                    date: input.date,
+                    dir: input.dir,
+                    comment: input.fileCommentStr.length ? input.fileCommentStr : null,
+                    unixPermissions: input.unixPermissions,
+                    dosPermissions: input.dosPermissions,
+                    createFolders: options.createFolders
+                });
+            }
+            if (zipEntries.zipComment.length) {
+                zip.comment = zipEntries.zipComment;
+            }
+
+            return zip;
+        });
+};
+
+},{"./external":6,"./nodejsUtils":14,"./stream/Crc32Probe":25,"./utf8":31,"./utils":32,"./zipEntries":33}],12:[function(require,module,exports){
+"use strict";
+
+var utils = require('../utils');
+var GenericWorker = require('../stream/GenericWorker');
+
+/**
+ * A worker that use a nodejs stream as source.
+ * @constructor
+ * @param {String} filename the name of the file entry for this stream.
+ * @param {Readable} stream the nodejs stream.
+ */
+function NodejsStreamInputAdapter(filename, stream) {
+    GenericWorker.call(this, "Nodejs stream input adapter for " + filename);
+    this._upstreamEnded = false;
+    this._bindStream(stream);
+}
+
+utils.inherits(NodejsStreamInputAdapter, GenericWorker);
+
+/**
+ * Prepare the stream and bind the callbacks on it.
+ * Do this ASAP on node 0.10 ! A lazy binding doesn't always work.
+ * @param {Stream} stream the nodejs stream to use.
+ */
+NodejsStreamInputAdapter.prototype._bindStream = function (stream) {
+    var self = this;
+    this._stream = stream;
+    stream.pause();
+    stream
+    .on("data", function (chunk) {
+        self.push({
+            data: chunk,
+            meta : {
+                percent : 0
+            }
+        });
+    })
+    .on("error", function (e) {
+        if(self.isPaused) {
+            this.generatedError = e;
+        } else {
+            self.error(e);
+        }
+    })
+    .on("end", function () {
+        if(self.isPaused) {
+            self._upstreamEnded = true;
+        } else {
+            self.end();
+        }
+    });
+};
+NodejsStreamInputAdapter.prototype.pause = function () {
+    if(!GenericWorker.prototype.pause.call(this)) {
+        return false;
+    }
+    this._stream.pause();
+    return true;
+};
+NodejsStreamInputAdapter.prototype.resume = function () {
+    if(!GenericWorker.prototype.resume.call(this)) {
+        return false;
+    }
+
+    if(this._upstreamEnded) {
+        this.end();
+    } else {
+        this._stream.resume();
+    }
+
+    return true;
+};
+
+module.exports = NodejsStreamInputAdapter;
+
+},{"../stream/GenericWorker":28,"../utils":32}],13:[function(require,module,exports){
+'use strict';
+
+var Readable = require('readable-stream').Readable;
+
+var utils = require('../utils');
+utils.inherits(NodejsStreamOutputAdapter, Readable);
+
+/**
+* A nodejs stream using a worker as source.
+* @see the SourceWrapper in http://nodejs.org/api/stream.html
+* @constructor
+* @param {StreamHelper} helper the helper wrapping the worker
+* @param {Object} options the nodejs stream options
+* @param {Function} updateCb the update callback.
+*/
+function NodejsStreamOutputAdapter(helper, options, updateCb) {
+    Readable.call(this, options);
+    this._helper = helper;
+
+    var self = this;
+    helper.on("data", function (data, meta) {
+        if (!self.push(data)) {
+            self._helper.pause();
+        }
+        if(updateCb) {
+            updateCb(meta);
+        }
+    })
+    .on("error", function(e) {
+        self.emit('error', e);
+    })
+    .on("end", function () {
+        self.push(null);
+    });
+}
+
+
+NodejsStreamOutputAdapter.prototype._read = function() {
+    this._helper.resume();
+};
+
+module.exports = NodejsStreamOutputAdapter;
+
+},{"../utils":32,"readable-stream":16}],14:[function(require,module,exports){
+'use strict';
+
+module.exports = {
+    /**
+     * True if this is running in Nodejs, will be undefined in a browser.
+     * In a browser, browserify won't include this file and the whole module
+     * will be resolved an empty object.
+     */
+    isNode : typeof Buffer !== "undefined",
+    /**
+     * Create a new nodejs Buffer from an existing content.
+     * @param {Object} data the data to pass to the constructor.
+     * @param {String} encoding the encoding to use.
+     * @return {Buffer} a new Buffer.
+     */
+    newBufferFrom: function(data, encoding) {
+        if (Buffer.from && Buffer.from !== Uint8Array.from) {
+            return Buffer.from(data, encoding);
+        } else {
+            if (typeof data === "number") {
+                // Safeguard for old Node.js versions. On newer versions,
+                // Buffer.from(number) / Buffer(number, encoding) already throw.
+                throw new Error("The \"data\" argument must not be a number");
+            }
+            return new Buffer(data, encoding);
+        }
+    },
+    /**
+     * Create a new nodejs Buffer with the specified size.
+     * @param {Integer} size the size of the buffer.
+     * @return {Buffer} a new Buffer.
+     */
+    allocBuffer: function (size) {
+        if (Buffer.alloc) {
+            return Buffer.alloc(size);
+        } else {
+            var buf = new Buffer(size);
+            buf.fill(0);
+            return buf;
+        }
+    },
+    /**
+     * Find out if an object is a Buffer.
+     * @param {Object} b the object to test.
+     * @return {Boolean} true if the object is a Buffer, false otherwise.
+     */
+    isBuffer : function(b){
+        return Buffer.isBuffer(b);
+    },
+
+    isStream : function (obj) {
+        return obj &&
+            typeof obj.on === "function" &&
+            typeof obj.pause === "function" &&
+            typeof obj.resume === "function";
+    }
+};
+
+},{}],15:[function(require,module,exports){
+'use strict';
+var utf8 = require('./utf8');
+var utils = require('./utils');
+var GenericWorker = require('./stream/GenericWorker');
+var StreamHelper = require('./stream/StreamHelper');
+var defaults = require('./defaults');
+var CompressedObject = require('./compressedObject');
+var ZipObject = require('./zipObject');
+var generate = require("./generate");
+var nodejsUtils = require("./nodejsUtils");
+var NodejsStreamInputAdapter = require("./nodejs/NodejsStreamInputAdapter");
+
+
+/**
+ * Add a file in the current folder.
+ * @private
+ * @param {string} name the name of the file
+ * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file
+ * @param {Object} originalOptions the options of the file
+ * @return {Object} the new file.
+ */
+var fileAdd = function(name, data, originalOptions) {
+    // be sure sub folders exist
+    var dataType = utils.getTypeOf(data),
+        parent;
+
+
+    /*
+     * Correct options.
+     */
+
+    var o = utils.extend(originalOptions || {}, defaults);
+    o.date = o.date || new Date();
+    if (o.compression !== null) {
+        o.compression = o.compression.toUpperCase();
+    }
+
+    if (typeof o.unixPermissions === "string") {
+        o.unixPermissions = parseInt(o.unixPermissions, 8);
+    }
+
+    // UNX_IFDIR  0040000 see zipinfo.c
+    if (o.unixPermissions && (o.unixPermissions & 0x4000)) {
+        o.dir = true;
+    }
+    // Bit 4    Directory
+    if (o.dosPermissions && (o.dosPermissions & 0x0010)) {
+        o.dir = true;
+    }
+
+    if (o.dir) {
+        name = forceTrailingSlash(name);
+    }
+    if (o.createFolders && (parent = parentFolder(name))) {
+        folderAdd.call(this, parent, true);
+    }
+
+    var isUnicodeString = dataType === "string" && o.binary === false && o.base64 === false;
+    if (!originalOptions || typeof originalOptions.binary === "undefined") {
+        o.binary = !isUnicodeString;
+    }
+
+
+    var isCompressedEmpty = (data instanceof CompressedObject) && data.uncompressedSize === 0;
+
+    if (isCompressedEmpty || o.dir || !data || data.length === 0) {
+        o.base64 = false;
+        o.binary = true;
+        data = "";
+        o.compression = "STORE";
+        dataType = "string";
+    }
+
+    /*
+     * Convert content to fit.
+     */
+
+    var zipObjectContent = null;
+    if (data instanceof CompressedObject || data instanceof GenericWorker) {
+        zipObjectContent = data;
+    } else if (nodejsUtils.isNode && nodejsUtils.isStream(data)) {
+        zipObjectContent = new NodejsStreamInputAdapter(name, data);
+    } else {
+        zipObjectContent = utils.prepareContent(name, data, o.binary, o.optimizedBinaryString, o.base64);
+    }
+
+    var object = new ZipObject(name, zipObjectContent, o);
+    this.files[name] = object;
+    /*
+    TODO: we can't throw an exception because we have async promises
+    (we can have a promise of a Date() for example) but returning a
+    promise is useless because file(name, data) returns the JSZip
+    object for chaining. Should we break that to allow the user
+    to catch the error ?
+
+    return external.Promise.resolve(zipObjectContent)
+    .then(function () {
+        return object;
+    });
+    */
+};
+
+/**
+ * Find the parent folder of the path.
+ * @private
+ * @param {string} path the path to use
+ * @return {string} the parent folder, or ""
+ */
+var parentFolder = function (path) {
+    if (path.slice(-1) === '/') {
+        path = path.substring(0, path.length - 1);
+    }
+    var lastSlash = path.lastIndexOf('/');
+    return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
+};
+
+/**
+ * Returns the path with a slash at the end.
+ * @private
+ * @param {String} path the path to check.
+ * @return {String} the path with a trailing slash.
+ */
+var forceTrailingSlash = function(path) {
+    // Check the name ends with a /
+    if (path.slice(-1) !== "/") {
+        path += "/"; // IE doesn't like substr(-1)
+    }
+    return path;
+};
+
+/**
+ * Add a (sub) folder in the current folder.
+ * @private
+ * @param {string} name the folder's name
+ * @param {boolean=} [createFolders] If true, automatically create sub
+ *  folders. Defaults to false.
+ * @return {Object} the new folder.
+ */
+var folderAdd = function(name, createFolders) {
+    createFolders = (typeof createFolders !== 'undefined') ? createFolders : defaults.createFolders;
+
+    name = forceTrailingSlash(name);
+
+    // Does this folder already exist?
+    if (!this.files[name]) {
+        fileAdd.call(this, name, null, {
+            dir: true,
+            createFolders: createFolders
+        });
+    }
+    return this.files[name];
+};
+
+/**
+* Cross-window, cross-Node-context regular expression detection
+* @param  {Object}  object Anything
+* @return {Boolean}        true if the object is a regular expression,
+* false otherwise
+*/
+function isRegExp(object) {
+    return Object.prototype.toString.call(object) === "[object RegExp]";
+}
+
+// return the actual prototype of JSZip
+var out = {
+    /**
+     * @see loadAsync
+     */
+    load: function() {
+        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
+    },
+
+
+    /**
+     * Call a callback function for each entry at this folder level.
+     * @param {Function} cb the callback function:
+     * function (relativePath, file) {...}
+     * It takes 2 arguments : the relative path and the file.
+     */
+    forEach: function(cb) {
+        var filename, relativePath, file;
+        /* jshint ignore:start */
+        // ignore warning about unwanted properties because this.files is a null prototype object
+        for (filename in this.files) {
+            file = this.files[filename];
+            relativePath = filename.slice(this.root.length, filename.length);
+            if (relativePath && filename.slice(0, this.root.length) === this.root) { // the file is in the current root
+                cb(relativePath, file); // TODO reverse the parameters ? need to be clean AND consistent with the filter search fn...
+            }
+        }
+        /* jshint ignore:end */
+    },
+
+    /**
+     * Filter nested files/folders with the specified function.
+     * @param {Function} search the predicate to use :
+     * function (relativePath, file) {...}
+     * It takes 2 arguments : the relative path and the file.
+     * @return {Array} An array of matching elements.
+     */
+    filter: function(search) {
+        var result = [];
+        this.forEach(function (relativePath, entry) {
+            if (search(relativePath, entry)) { // the file matches the function
+                result.push(entry);
+            }
+
+        });
+        return result;
+    },
+
+    /**
+     * Add a file to the zip file, or search a file.
+     * @param   {string|RegExp} name The name of the file to add (if data is defined),
+     * the name of the file to find (if no data) or a regex to match files.
+     * @param   {String|ArrayBuffer|Uint8Array|Buffer} data  The file data, either raw or base64 encoded
+     * @param   {Object} o     File options
+     * @return  {JSZip|Object|Array} this JSZip object (when adding a file),
+     * a file (when searching by string) or an array of files (when searching by regex).
+     */
+    file: function(name, data, o) {
+        if (arguments.length === 1) {
+            if (isRegExp(name)) {
+                var regexp = name;
+                return this.filter(function(relativePath, file) {
+                    return !file.dir && regexp.test(relativePath);
+                });
+            }
+            else { // text
+                var obj = this.files[this.root + name];
+                if (obj && !obj.dir) {
+                    return obj;
+                } else {
+                    return null;
+                }
+            }
+        }
+        else { // more than one argument : we have data !
+            name = this.root + name;
+            fileAdd.call(this, name, data, o);
+        }
+        return this;
+    },
+
+    /**
+     * Add a directory to the zip file, or search.
+     * @param   {String|RegExp} arg The name of the directory to add, or a regex to search folders.
+     * @return  {JSZip} an object with the new directory as the root, or an array containing matching folders.
+     */
+    folder: function(arg) {
+        if (!arg) {
+            return this;
+        }
+
+        if (isRegExp(arg)) {
+            return this.filter(function(relativePath, file) {
+                return file.dir && arg.test(relativePath);
+            });
+        }
+
+        // else, name is a new folder
+        var name = this.root + arg;
+        var newFolder = folderAdd.call(this, name);
+
+        // Allow chaining by returning a new object with this folder as the root
+        var ret = this.clone();
+        ret.root = newFolder.name;
+        return ret;
+    },
+
+    /**
+     * Delete a file, or a directory and all sub-files, from the zip
+     * @param {string} name the name of the file to delete
+     * @return {JSZip} this JSZip object
+     */
+    remove: function(name) {
+        name = this.root + name;
+        var file = this.files[name];
+        if (!file) {
+            // Look for any folders
+            if (name.slice(-1) !== "/") {
+                name += "/";
+            }
+            file = this.files[name];
+        }
+
+        if (file && !file.dir) {
+            // file
+            delete this.files[name];
+        } else {
+            // maybe a folder, delete recursively
+            var kids = this.filter(function(relativePath, file) {
+                return file.name.slice(0, name.length) === name;
+            });
+            for (var i = 0; i < kids.length; i++) {
+                delete this.files[kids[i].name];
+            }
+        }
+
+        return this;
+    },
+
+    /**
+     * Generate the complete zip file
+     * @param {Object} options the options to generate the zip file :
+     * - compression, "STORE" by default.
+     * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
+     * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file
+     */
+    generate: function(options) {
+        throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
+    },
+
+    /**
+     * Generate the complete zip file as an internal stream.
+     * @param {Object} options the options to generate the zip file :
+     * - compression, "STORE" by default.
+     * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
+     * @return {StreamHelper} the streamed zip file.
+     */
+    generateInternalStream: function(options) {
+      var worker, opts = {};
+      try {
+          opts = utils.extend(options || {}, {
+              streamFiles: false,
+              compression: "STORE",
+              compressionOptions : null,
+              type: "",
+              platform: "DOS",
+              comment: null,
+              mimeType: 'application/zip',
+              encodeFileName: utf8.utf8encode
+          });
+
+          opts.type = opts.type.toLowerCase();
+          opts.compression = opts.compression.toUpperCase();
+
+          // "binarystring" is preferred but the internals use "string".
+          if(opts.type === "binarystring") {
+            opts.type = "string";
+          }
+
+          if (!opts.type) {
+            throw new Error("No output type specified.");
+          }
+
+          utils.checkSupport(opts.type);
+
+          // accept nodejs `process.platform`
+          if(
+              opts.platform === 'darwin' ||
+              opts.platform === 'freebsd' ||
+              opts.platform === 'linux' ||
+              opts.platform === 'sunos'
+          ) {
+              opts.platform = "UNIX";
+          }
+          if (opts.platform === 'win32') {
+              opts.platform = "DOS";
+          }
+
+          var comment = opts.comment || this.comment || "";
+          worker = generate.generateWorker(this, opts, comment);
+      } catch (e) {
+        worker = new GenericWorker("error");
+        worker.error(e);
+      }
+      return new StreamHelper(worker, opts.type || "string", opts.mimeType);
+    },
+    /**
+     * Generate the complete zip file asynchronously.
+     * @see generateInternalStream
+     */
+    generateAsync: function(options, onUpdate) {
+        return this.generateInternalStream(options).accumulate(onUpdate);
+    },
+    /**
+     * Generate the complete zip file asynchronously.
+     * @see generateInternalStream
+     */
+    generateNodeStream: function(options, onUpdate) {
+        options = options || {};
+        if (!options.type) {
+            options.type = "nodebuffer";
+        }
+        return this.generateInternalStream(options).toNodejsStream(onUpdate);
+    }
+};
+module.exports = out;
+
+},{"./compressedObject":2,"./defaults":5,"./generate":9,"./nodejs/NodejsStreamInputAdapter":12,"./nodejsUtils":14,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31,"./utils":32,"./zipObject":35}],16:[function(require,module,exports){
+/*
+ * This file is used by module bundlers (browserify/webpack/etc) when
+ * including a stream implementation. We use "readable-stream" to get a
+ * consistent behavior between nodejs versions but bundlers often have a shim
+ * for "stream". Using this shim greatly improve the compatibility and greatly
+ * reduce the final size of the bundle (only one stream implementation, not
+ * two).
+ */
+module.exports = require("stream");
+
+},{"stream":undefined}],17:[function(require,module,exports){
+'use strict';
+var DataReader = require('./DataReader');
+var utils = require('../utils');
+
+function ArrayReader(data) {
+    DataReader.call(this, data);
+       for(var i = 0; i < this.data.length; i++) {
+               data[i] = data[i] & 0xFF;
+       }
+}
+utils.inherits(ArrayReader, DataReader);
+/**
+ * @see DataReader.byteAt
+ */
+ArrayReader.prototype.byteAt = function(i) {
+    return this.data[this.zero + i];
+};
+/**
+ * @see DataReader.lastIndexOfSignature
+ */
+ArrayReader.prototype.lastIndexOfSignature = function(sig) {
+    var sig0 = sig.charCodeAt(0),
+        sig1 = sig.charCodeAt(1),
+        sig2 = sig.charCodeAt(2),
+        sig3 = sig.charCodeAt(3);
+    for (var i = this.length - 4; i >= 0; --i) {
+        if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) {
+            return i - this.zero;
+        }
+    }
+
+    return -1;
+};
+/**
+ * @see DataReader.readAndCheckSignature
+ */
+ArrayReader.prototype.readAndCheckSignature = function (sig) {
+    var sig0 = sig.charCodeAt(0),
+        sig1 = sig.charCodeAt(1),
+        sig2 = sig.charCodeAt(2),
+        sig3 = sig.charCodeAt(3),
+        data = this.readData(4);
+    return sig0 === data[0] && sig1 === data[1] && sig2 === data[2] && sig3 === data[3];
+};
+/**
+ * @see DataReader.readData
+ */
+ArrayReader.prototype.readData = function(size) {
+    this.checkOffset(size);
+    if(size === 0) {
+        return [];
+    }
+    var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
+    this.index += size;
+    return result;
+};
+module.exports = ArrayReader;
+
+},{"../utils":32,"./DataReader":18}],18:[function(require,module,exports){
+'use strict';
+var utils = require('../utils');
+
+function DataReader(data) {
+    this.data = data; // type : see implementation
+    this.length = data.length;
+    this.index = 0;
+    this.zero = 0;
+}
+DataReader.prototype = {
+    /**
+     * Check that the offset will not go too far.
+     * @param {string} offset the additional offset to check.
+     * @throws {Error} an Error if the offset is out of bounds.
+     */
+    checkOffset: function(offset) {
+        this.checkIndex(this.index + offset);
+    },
+    /**
+     * Check that the specified index will not be too far.
+     * @param {string} newIndex the index to check.
+     * @throws {Error} an Error if the index is out of bounds.
+     */
+    checkIndex: function(newIndex) {
+        if (this.length < this.zero + newIndex || newIndex < 0) {
+            throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?");
+        }
+    },
+    /**
+     * Change the index.
+     * @param {number} newIndex The new index.
+     * @throws {Error} if the new index is out of the data.
+     */
+    setIndex: function(newIndex) {
+        this.checkIndex(newIndex);
+        this.index = newIndex;
+    },
+    /**
+     * Skip the next n bytes.
+     * @param {number} n the number of bytes to skip.
+     * @throws {Error} if the new index is out of the data.
+     */
+    skip: function(n) {
+        this.setIndex(this.index + n);
+    },
+    /**
+     * Get the byte at the specified index.
+     * @param {number} i the index to use.
+     * @return {number} a byte.
+     */
+    byteAt: function(i) {
+        // see implementations
+    },
+    /**
+     * Get the next number with a given byte size.
+     * @param {number} size the number of bytes to read.
+     * @return {number} the corresponding number.
+     */
+    readInt: function(size) {
+        var result = 0,
+            i;
+        this.checkOffset(size);
+        for (i = this.index + size - 1; i >= this.index; i--) {
+            result = (result << 8) + this.byteAt(i);
+        }
+        this.index += size;
+        return result;
+    },
+    /**
+     * Get the next string with a given byte size.
+     * @param {number} size the number of bytes to read.
+     * @return {string} the corresponding string.
+     */
+    readString: function(size) {
+        return utils.transformTo("string", this.readData(size));
+    },
+    /**
+     * Get raw data without conversion, <size> bytes.
+     * @param {number} size the number of bytes to read.
+     * @return {Object} the raw data, implementation specific.
+     */
+    readData: function(size) {
+        // see implementations
+    },
+    /**
+     * Find the last occurrence of a zip signature (4 bytes).
+     * @param {string} sig the signature to find.
+     * @return {number} the index of the last occurrence, -1 if not found.
+     */
+    lastIndexOfSignature: function(sig) {
+        // see implementations
+    },
+    /**
+     * Read the signature (4 bytes) at the current position and compare it with sig.
+     * @param {string} sig the expected signature
+     * @return {boolean} true if the signature matches, false otherwise.
+     */
+    readAndCheckSignature: function(sig) {
+        // see implementations
+    },
+    /**
+     * Get the next date.
+     * @return {Date} the date.
+     */
+    readDate: function() {
+        var dostime = this.readInt(4);
+        return new Date(Date.UTC(
+        ((dostime >> 25) & 0x7f) + 1980, // year
+        ((dostime >> 21) & 0x0f) - 1, // month
+        (dostime >> 16) & 0x1f, // day
+        (dostime >> 11) & 0x1f, // hour
+        (dostime >> 5) & 0x3f, // minute
+        (dostime & 0x1f) << 1)); // second
+    }
+};
+module.exports = DataReader;
+
+},{"../utils":32}],19:[function(require,module,exports){
+'use strict';
+var Uint8ArrayReader = require('./Uint8ArrayReader');
+var utils = require('../utils');
+
+function NodeBufferReader(data) {
+    Uint8ArrayReader.call(this, data);
+}
+utils.inherits(NodeBufferReader, Uint8ArrayReader);
+
+/**
+ * @see DataReader.readData
+ */
+NodeBufferReader.prototype.readData = function(size) {
+    this.checkOffset(size);
+    var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
+    this.index += size;
+    return result;
+};
+module.exports = NodeBufferReader;
+
+},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(require,module,exports){
+'use strict';
+var DataReader = require('./DataReader');
+var utils = require('../utils');
+
+function StringReader(data) {
+    DataReader.call(this, data);
+}
+utils.inherits(StringReader, DataReader);
+/**
+ * @see DataReader.byteAt
+ */
+StringReader.prototype.byteAt = function(i) {
+    return this.data.charCodeAt(this.zero + i);
+};
+/**
+ * @see DataReader.lastIndexOfSignature
+ */
+StringReader.prototype.lastIndexOfSignature = function(sig) {
+    return this.data.lastIndexOf(sig) - this.zero;
+};
+/**
+ * @see DataReader.readAndCheckSignature
+ */
+StringReader.prototype.readAndCheckSignature = function (sig) {
+    var data = this.readData(4);
+    return sig === data;
+};
+/**
+ * @see DataReader.readData
+ */
+StringReader.prototype.readData = function(size) {
+    this.checkOffset(size);
+    // this will work because the constructor applied the "& 0xff" mask.
+    var result = this.data.slice(this.zero + this.index, this.zero + this.index + size);
+    this.index += size;
+    return result;
+};
+module.exports = StringReader;
+
+},{"../utils":32,"./DataReader":18}],21:[function(require,module,exports){
+'use strict';
+var ArrayReader = require('./ArrayReader');
+var utils = require('../utils');
+
+function Uint8ArrayReader(data) {
+    ArrayReader.call(this, data);
+}
+utils.inherits(Uint8ArrayReader, ArrayReader);
+/**
+ * @see DataReader.readData
+ */
+Uint8ArrayReader.prototype.readData = function(size) {
+    this.checkOffset(size);
+    if(size === 0) {
+        // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].
+        return new Uint8Array(0);
+    }
+    var result = this.data.subarray(this.zero + this.index, this.zero + this.index + size);
+    this.index += size;
+    return result;
+};
+module.exports = Uint8ArrayReader;
+
+},{"../utils":32,"./ArrayReader":17}],22:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var support = require('../support');
+var ArrayReader = require('./ArrayReader');
+var StringReader = require('./StringReader');
+var NodeBufferReader = require('./NodeBufferReader');
+var Uint8ArrayReader = require('./Uint8ArrayReader');
+
+/**
+ * Create a reader adapted to the data.
+ * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data to read.
+ * @return {DataReader} the data reader.
+ */
+module.exports = function (data) {
+    var type = utils.getTypeOf(data);
+    utils.checkSupport(type);
+    if (type === "string" && !support.uint8array) {
+        return new StringReader(data);
+    }
+    if (type === "nodebuffer") {
+        return new NodeBufferReader(data);
+    }
+    if (support.uint8array) {
+        return new Uint8ArrayReader(utils.transformTo("uint8array", data));
+    }
+    return new ArrayReader(utils.transformTo("array", data));
+};
+
+},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(require,module,exports){
+'use strict';
+exports.LOCAL_FILE_HEADER = "PK\x03\x04";
+exports.CENTRAL_FILE_HEADER = "PK\x01\x02";
+exports.CENTRAL_DIRECTORY_END = "PK\x05\x06";
+exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07";
+exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06";
+exports.DATA_DESCRIPTOR = "PK\x07\x08";
+
+},{}],24:[function(require,module,exports){
+'use strict';
+
+var GenericWorker = require('./GenericWorker');
+var utils = require('../utils');
+
+/**
+ * A worker which convert chunks to a specified type.
+ * @constructor
+ * @param {String} destType the destination type.
+ */
+function ConvertWorker(destType) {
+    GenericWorker.call(this, "ConvertWorker to " + destType);
+    this.destType = destType;
+}
+utils.inherits(ConvertWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+ConvertWorker.prototype.processChunk = function (chunk) {
+    this.push({
+        data : utils.transformTo(this.destType, chunk.data),
+        meta : chunk.meta
+    });
+};
+module.exports = ConvertWorker;
+
+},{"../utils":32,"./GenericWorker":28}],25:[function(require,module,exports){
+'use strict';
+
+var GenericWorker = require('./GenericWorker');
+var crc32 = require('../crc32');
+var utils = require('../utils');
+
+/**
+ * A worker which calculate the crc32 of the data flowing through.
+ * @constructor
+ */
+function Crc32Probe() {
+    GenericWorker.call(this, "Crc32Probe");
+    this.withStreamInfo("crc32", 0);
+}
+utils.inherits(Crc32Probe, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+Crc32Probe.prototype.processChunk = function (chunk) {
+    this.streamInfo.crc32 = crc32(chunk.data, this.streamInfo.crc32 || 0);
+    this.push(chunk);
+};
+module.exports = Crc32Probe;
+
+},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var GenericWorker = require('./GenericWorker');
+
+/**
+ * A worker which calculate the total length of the data flowing through.
+ * @constructor
+ * @param {String} propName the name used to expose the length
+ */
+function DataLengthProbe(propName) {
+    GenericWorker.call(this, "DataLengthProbe for " + propName);
+    this.propName = propName;
+    this.withStreamInfo(propName, 0);
+}
+utils.inherits(DataLengthProbe, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+DataLengthProbe.prototype.processChunk = function (chunk) {
+    if(chunk) {
+        var length = this.streamInfo[this.propName] || 0;
+        this.streamInfo[this.propName] = length + chunk.data.length;
+    }
+    GenericWorker.prototype.processChunk.call(this, chunk);
+};
+module.exports = DataLengthProbe;
+
+
+},{"../utils":32,"./GenericWorker":28}],27:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var GenericWorker = require('./GenericWorker');
+
+// the size of the generated chunks
+// TODO expose this as a public variable
+var DEFAULT_BLOCK_SIZE = 16 * 1024;
+
+/**
+ * A worker that reads a content and emits chunks.
+ * @constructor
+ * @param {Promise} dataP the promise of the data to split
+ */
+function DataWorker(dataP) {
+    GenericWorker.call(this, "DataWorker");
+    var self = this;
+    this.dataIsReady = false;
+    this.index = 0;
+    this.max = 0;
+    this.data = null;
+    this.type = "";
+
+    this._tickScheduled = false;
+
+    dataP.then(function (data) {
+        self.dataIsReady = true;
+        self.data = data;
+        self.max = data && data.length || 0;
+        self.type = utils.getTypeOf(data);
+        if(!self.isPaused) {
+            self._tickAndRepeat();
+        }
+    }, function (e) {
+        self.error(e);
+    });
+}
+
+utils.inherits(DataWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.cleanUp
+ */
+DataWorker.prototype.cleanUp = function () {
+    GenericWorker.prototype.cleanUp.call(this);
+    this.data = null;
+};
+
+/**
+ * @see GenericWorker.resume
+ */
+DataWorker.prototype.resume = function () {
+    if(!GenericWorker.prototype.resume.call(this)) {
+        return false;
+    }
+
+    if (!this._tickScheduled && this.dataIsReady) {
+        this._tickScheduled = true;
+        utils.delay(this._tickAndRepeat, [], this);
+    }
+    return true;
+};
+
+/**
+ * Trigger a tick a schedule an other call to this function.
+ */
+DataWorker.prototype._tickAndRepeat = function() {
+    this._tickScheduled = false;
+    if(this.isPaused || this.isFinished) {
+        return;
+    }
+    this._tick();
+    if(!this.isFinished) {
+        utils.delay(this._tickAndRepeat, [], this);
+        this._tickScheduled = true;
+    }
+};
+
+/**
+ * Read and push a chunk.
+ */
+DataWorker.prototype._tick = function() {
+
+    if(this.isPaused || this.isFinished) {
+        return false;
+    }
+
+    var size = DEFAULT_BLOCK_SIZE;
+    var data = null, nextIndex = Math.min(this.max, this.index + size);
+    if (this.index >= this.max) {
+        // EOF
+        return this.end();
+    } else {
+        switch(this.type) {
+            case "string":
+                data = this.data.substring(this.index, nextIndex);
+            break;
+            case "uint8array":
+                data = this.data.subarray(this.index, nextIndex);
+            break;
+            case "array":
+            case "nodebuffer":
+                data = this.data.slice(this.index, nextIndex);
+            break;
+        }
+        this.index = nextIndex;
+        return this.push({
+            data : data,
+            meta : {
+                percent : this.max ? this.index / this.max * 100 : 0
+            }
+        });
+    }
+};
+
+module.exports = DataWorker;
+
+},{"../utils":32,"./GenericWorker":28}],28:[function(require,module,exports){
+'use strict';
+
+/**
+ * A worker that does nothing but passing chunks to the next one. This is like
+ * a nodejs stream but with some differences. On the good side :
+ * - it works on IE 6-9 without any issue / polyfill
+ * - it weights less than the full dependencies bundled with browserify
+ * - it forwards errors (no need to declare an error handler EVERYWHERE)
+ *
+ * A chunk is an object with 2 attributes : `meta` and `data`. The former is an
+ * object containing anything (`percent` for example), see each worker for more
+ * details. The latter is the real data (String, Uint8Array, etc).
+ *
+ * @constructor
+ * @param {String} name the name of the stream (mainly used for debugging purposes)
+ */
+function GenericWorker(name) {
+    // the name of the worker
+    this.name = name || "default";
+    // an object containing metadata about the workers chain
+    this.streamInfo = {};
+    // an error which happened when the worker was paused
+    this.generatedError = null;
+    // an object containing metadata to be merged by this worker into the general metadata
+    this.extraStreamInfo = {};
+    // true if the stream is paused (and should not do anything), false otherwise
+    this.isPaused = true;
+    // true if the stream is finished (and should not do anything), false otherwise
+    this.isFinished = false;
+    // true if the stream is locked to prevent further structure updates (pipe), false otherwise
+    this.isLocked = false;
+    // the event listeners
+    this._listeners = {
+        'data':[],
+        'end':[],
+        'error':[]
+    };
+    // the previous worker, if any
+    this.previous = null;
+}
+
+GenericWorker.prototype = {
+    /**
+     * Push a chunk to the next workers.
+     * @param {Object} chunk the chunk to push
+     */
+    push : function (chunk) {
+        this.emit("data", chunk);
+    },
+    /**
+     * End the stream.
+     * @return {Boolean} true if this call ended the worker, false otherwise.
+     */
+    end : function () {
+        if (this.isFinished) {
+            return false;
+        }
+
+        this.flush();
+        try {
+            this.emit("end");
+            this.cleanUp();
+            this.isFinished = true;
+        } catch (e) {
+            this.emit("error", e);
+        }
+        return true;
+    },
+    /**
+     * End the stream with an error.
+     * @param {Error} e the error which caused the premature end.
+     * @return {Boolean} true if this call ended the worker with an error, false otherwise.
+     */
+    error : function (e) {
+        if (this.isFinished) {
+            return false;
+        }
+
+        if(this.isPaused) {
+            this.generatedError = e;
+        } else {
+            this.isFinished = true;
+
+            this.emit("error", e);
+
+            // in the workers chain exploded in the middle of the chain,
+            // the error event will go downward but we also need to notify
+            // workers upward that there has been an error.
+            if(this.previous) {
+                this.previous.error(e);
+            }
+
+            this.cleanUp();
+        }
+        return true;
+    },
+    /**
+     * Add a callback on an event.
+     * @param {String} name the name of the event (data, end, error)
+     * @param {Function} listener the function to call when the event is triggered
+     * @return {GenericWorker} the current object for chainability
+     */
+    on : function (name, listener) {
+        this._listeners[name].push(listener);
+        return this;
+    },
+    /**
+     * Clean any references when a worker is ending.
+     */
+    cleanUp : function () {
+        this.streamInfo = this.generatedError = this.extraStreamInfo = null;
+        this._listeners = [];
+    },
+    /**
+     * Trigger an event. This will call registered callback with the provided arg.
+     * @param {String} name the name of the event (data, end, error)
+     * @param {Object} arg the argument to call the callback with.
+     */
+    emit : function (name, arg) {
+        if (this._listeners[name]) {
+            for(var i = 0; i < this._listeners[name].length; i++) {
+                this._listeners[name][i].call(this, arg);
+            }
+        }
+    },
+    /**
+     * Chain a worker with an other.
+     * @param {Worker} next the worker receiving events from the current one.
+     * @return {worker} the next worker for chainability
+     */
+    pipe : function (next) {
+        return next.registerPrevious(this);
+    },
+    /**
+     * Same as `pipe` in the other direction.
+     * Using an API with `pipe(next)` is very easy.
+     * Implementing the API with the point of view of the next one registering
+     * a source is easier, see the ZipFileWorker.
+     * @param {Worker} previous the previous worker, sending events to this one
+     * @return {Worker} the current worker for chainability
+     */
+    registerPrevious : function (previous) {
+        if (this.isLocked) {
+            throw new Error("The stream '" + this + "' has already been used.");
+        }
+
+        // sharing the streamInfo...
+        this.streamInfo = previous.streamInfo;
+        // ... and adding our own bits
+        this.mergeStreamInfo();
+        this.previous =  previous;
+        var self = this;
+        previous.on('data', function (chunk) {
+            self.processChunk(chunk);
+        });
+        previous.on('end', function () {
+            self.end();
+        });
+        previous.on('error', function (e) {
+            self.error(e);
+        });
+        return this;
+    },
+    /**
+     * Pause the stream so it doesn't send events anymore.
+     * @return {Boolean} true if this call paused the worker, false otherwise.
+     */
+    pause : function () {
+        if(this.isPaused || this.isFinished) {
+            return false;
+        }
+        this.isPaused = true;
+
+        if(this.previous) {
+            this.previous.pause();
+        }
+        return true;
+    },
+    /**
+     * Resume a paused stream.
+     * @return {Boolean} true if this call resumed the worker, false otherwise.
+     */
+    resume : function () {
+        if(!this.isPaused || this.isFinished) {
+            return false;
+        }
+        this.isPaused = false;
+
+        // if true, the worker tried to resume but failed
+        var withError = false;
+        if(this.generatedError) {
+            this.error(this.generatedError);
+            withError = true;
+        }
+        if(this.previous) {
+            this.previous.resume();
+        }
+
+        return !withError;
+    },
+    /**
+     * Flush any remaining bytes as the stream is ending.
+     */
+    flush : function () {},
+    /**
+     * Process a chunk. This is usually the method overridden.
+     * @param {Object} chunk the chunk to process.
+     */
+    processChunk : function(chunk) {
+        this.push(chunk);
+    },
+    /**
+     * Add a key/value to be added in the workers chain streamInfo once activated.
+     * @param {String} key the key to use
+     * @param {Object} value the associated value
+     * @return {Worker} the current worker for chainability
+     */
+    withStreamInfo : function (key, value) {
+        this.extraStreamInfo[key] = value;
+        this.mergeStreamInfo();
+        return this;
+    },
+    /**
+     * Merge this worker's streamInfo into the chain's streamInfo.
+     */
+    mergeStreamInfo : function () {
+        for(var key in this.extraStreamInfo) {
+            if (!this.extraStreamInfo.hasOwnProperty(key)) {
+                continue;
+            }
+            this.streamInfo[key] = this.extraStreamInfo[key];
+        }
+    },
+
+    /**
+     * Lock the stream to prevent further updates on the workers chain.
+     * After calling this method, all calls to pipe will fail.
+     */
+    lock: function () {
+        if (this.isLocked) {
+            throw new Error("The stream '" + this + "' has already been used.");
+        }
+        this.isLocked = true;
+        if (this.previous) {
+            this.previous.lock();
+        }
+    },
+
+    /**
+     *
+     * Pretty print the workers chain.
+     */
+    toString : function () {
+        var me = "Worker " + this.name;
+        if (this.previous) {
+            return this.previous + " -> " + me;
+        } else {
+            return me;
+        }
+    }
+};
+
+module.exports = GenericWorker;
+
+},{}],29:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var ConvertWorker = require('./ConvertWorker');
+var GenericWorker = require('./GenericWorker');
+var base64 = require('../base64');
+var support = require("../support");
+var external = require("../external");
+
+var NodejsStreamOutputAdapter = null;
+if (support.nodestream) {
+    try {
+        NodejsStreamOutputAdapter = require('../nodejs/NodejsStreamOutputAdapter');
+    } catch(e) {}
+}
+
+/**
+ * Apply the final transformation of the data. If the user wants a Blob for
+ * example, it's easier to work with an U8intArray and finally do the
+ * ArrayBuffer/Blob conversion.
+ * @param {String} type the name of the final type
+ * @param {String|Uint8Array|Buffer} content the content to transform
+ * @param {String} mimeType the mime type of the content, if applicable.
+ * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the content in the right format.
+ */
+function transformZipOutput(type, content, mimeType) {
+    switch(type) {
+        case "blob" :
+            return utils.newBlob(utils.transformTo("arraybuffer", content), mimeType);
+        case "base64" :
+            return base64.encode(content);
+        default :
+            return utils.transformTo(type, content);
+    }
+}
+
+/**
+ * Concatenate an array of data of the given type.
+ * @param {String} type the type of the data in the given array.
+ * @param {Array} dataArray the array containing the data chunks to concatenate
+ * @return {String|Uint8Array|Buffer} the concatenated data
+ * @throws Error if the asked type is unsupported
+ */
+function concat (type, dataArray) {
+    var i, index = 0, res = null, totalLength = 0;
+    for(i = 0; i < dataArray.length; i++) {
+        totalLength += dataArray[i].length;
+    }
+    switch(type) {
+        case "string":
+            return dataArray.join("");
+          case "array":
+            return Array.prototype.concat.apply([], dataArray);
+        case "uint8array":
+            res = new Uint8Array(totalLength);
+            for(i = 0; i < dataArray.length; i++) {
+                res.set(dataArray[i], index);
+                index += dataArray[i].length;
+            }
+            return res;
+        case "nodebuffer":
+            return Buffer.concat(dataArray);
+        default:
+            throw new Error("concat : unsupported type '"  + type + "'");
+    }
+}
+
+/**
+ * Listen a StreamHelper, accumulate its content and concatenate it into a
+ * complete block.
+ * @param {StreamHelper} helper the helper to use.
+ * @param {Function} updateCallback a callback called on each update. Called
+ * with one arg :
+ * - the metadata linked to the update received.
+ * @return Promise the promise for the accumulation.
+ */
+function accumulate(helper, updateCallback) {
+    return new external.Promise(function (resolve, reject){
+        var dataArray = [];
+        var chunkType = helper._internalType,
+            resultType = helper._outputType,
+            mimeType = helper._mimeType;
+        helper
+        .on('data', function (data, meta) {
+            dataArray.push(data);
+            if(updateCallback) {
+                updateCallback(meta);
+            }
+        })
+        .on('error', function(err) {
+            dataArray = [];
+            reject(err);
+        })
+        .on('end', function (){
+            try {
+                var result = transformZipOutput(resultType, concat(chunkType, dataArray), mimeType);
+                resolve(result);
+            } catch (e) {
+                reject(e);
+            }
+            dataArray = [];
+        })
+        .resume();
+    });
+}
+
+/**
+ * An helper to easily use workers outside of JSZip.
+ * @constructor
+ * @param {Worker} worker the worker to wrap
+ * @param {String} outputType the type of data expected by the use
+ * @param {String} mimeType the mime type of the content, if applicable.
+ */
+function StreamHelper(worker, outputType, mimeType) {
+    var internalType = outputType;
+    switch(outputType) {
+        case "blob":
+        case "arraybuffer":
+            internalType = "uint8array";
+        break;
+        case "base64":
+            internalType = "string";
+        break;
+    }
+
+    try {
+        // the type used internally
+        this._internalType = internalType;
+        // the type used to output results
+        this._outputType = outputType;
+        // the mime type
+        this._mimeType = mimeType;
+        utils.checkSupport(internalType);
+        this._worker = worker.pipe(new ConvertWorker(internalType));
+        // the last workers can be rewired without issues but we need to
+        // prevent any updates on previous workers.
+        worker.lock();
+    } catch(e) {
+        this._worker = new GenericWorker("error");
+        this._worker.error(e);
+    }
+}
+
+StreamHelper.prototype = {
+    /**
+     * Listen a StreamHelper, accumulate its content and concatenate it into a
+     * complete block.
+     * @param {Function} updateCb the update callback.
+     * @return Promise the promise for the accumulation.
+     */
+    accumulate : function (updateCb) {
+        return accumulate(this, updateCb);
+    },
+    /**
+     * Add a listener on an event triggered on a stream.
+     * @param {String} evt the name of the event
+     * @param {Function} fn the listener
+     * @return {StreamHelper} the current helper.
+     */
+    on : function (evt, fn) {
+        var self = this;
+
+        if(evt === "data") {
+            this._worker.on(evt, function (chunk) {
+                fn.call(self, chunk.data, chunk.meta);
+            });
+        } else {
+            this._worker.on(evt, function () {
+                utils.delay(fn, arguments, self);
+            });
+        }
+        return this;
+    },
+    /**
+     * Resume the flow of chunks.
+     * @return {StreamHelper} the current helper.
+     */
+    resume : function () {
+        utils.delay(this._worker.resume, [], this._worker);
+        return this;
+    },
+    /**
+     * Pause the flow of chunks.
+     * @return {StreamHelper} the current helper.
+     */
+    pause : function () {
+        this._worker.pause();
+        return this;
+    },
+    /**
+     * Return a nodejs stream for this helper.
+     * @param {Function} updateCb the update callback.
+     * @return {NodejsStreamOutputAdapter} the nodejs stream.
+     */
+    toNodejsStream : function (updateCb) {
+        utils.checkSupport("nodestream");
+        if (this._outputType !== "nodebuffer") {
+            // an object stream containing blob/arraybuffer/uint8array/string
+            // is strange and I don't know if it would be useful.
+            // I you find this comment and have a good usecase, please open a
+            // bug report !
+            throw new Error(this._outputType + " is not supported by this method");
+        }
+
+        return new NodejsStreamOutputAdapter(this, {
+            objectMode : this._outputType !== "nodebuffer"
+        }, updateCb);
+    }
+};
+
+
+module.exports = StreamHelper;
+
+},{"../base64":1,"../external":6,"../nodejs/NodejsStreamOutputAdapter":13,"../support":30,"../utils":32,"./ConvertWorker":24,"./GenericWorker":28}],30:[function(require,module,exports){
+'use strict';
+
+exports.base64 = true;
+exports.array = true;
+exports.string = true;
+exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined";
+exports.nodebuffer = typeof Buffer !== "undefined";
+// contains true if JSZip can read/generate Uint8Array, false otherwise.
+exports.uint8array = typeof Uint8Array !== "undefined";
+
+if (typeof ArrayBuffer === "undefined") {
+    exports.blob = false;
+}
+else {
+    var buffer = new ArrayBuffer(0);
+    try {
+        exports.blob = new Blob([buffer], {
+            type: "application/zip"
+        }).size === 0;
+    }
+    catch (e) {
+        try {
+            var Builder = self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder;
+            var builder = new Builder();
+            builder.append(buffer);
+            exports.blob = builder.getBlob('application/zip').size === 0;
+        }
+        catch (e) {
+            exports.blob = false;
+        }
+    }
+}
+
+try {
+    exports.nodestream = !!require('readable-stream').Readable;
+} catch(e) {
+    exports.nodestream = false;
+}
+
+},{"readable-stream":16}],31:[function(require,module,exports){
+'use strict';
+
+var utils = require('./utils');
+var support = require('./support');
+var nodejsUtils = require('./nodejsUtils');
+var GenericWorker = require('./stream/GenericWorker');
+
+/**
+ * The following functions come from pako, from pako/lib/utils/strings
+ * released under the MIT license, see pako https://github.com/nodeca/pako/
+ */
+
+// Table with utf8 lengths (calculated by first byte of sequence)
+// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
+// because max possible codepoint is 0x10ffff
+var _utf8len = new Array(256);
+for (var i=0; i<256; i++) {
+  _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
+}
+_utf8len[254]=_utf8len[254]=1; // Invalid sequence start
+
+// convert string to array (typed, when possible)
+var string2buf = function (str) {
+    var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
+
+    // count binary size
+    for (m_pos = 0; m_pos < str_len; m_pos++) {
+        c = str.charCodeAt(m_pos);
+        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
+            c2 = str.charCodeAt(m_pos+1);
+            if ((c2 & 0xfc00) === 0xdc00) {
+                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+                m_pos++;
+            }
+        }
+        buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
+    }
+
+    // allocate buffer
+    if (support.uint8array) {
+        buf = new Uint8Array(buf_len);
+    } else {
+        buf = new Array(buf_len);
+    }
+
+    // convert
+    for (i=0, m_pos = 0; i < buf_len; m_pos++) {
+        c = str.charCodeAt(m_pos);
+        if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
+            c2 = str.charCodeAt(m_pos+1);
+            if ((c2 & 0xfc00) === 0xdc00) {
+                c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+                m_pos++;
+            }
+        }
+        if (c < 0x80) {
+            /* one byte */
+            buf[i++] = c;
+        } else if (c < 0x800) {
+            /* two bytes */
+            buf[i++] = 0xC0 | (c >>> 6);
+            buf[i++] = 0x80 | (c & 0x3f);
+        } else if (c < 0x10000) {
+            /* three bytes */
+            buf[i++] = 0xE0 | (c >>> 12);
+            buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+            buf[i++] = 0x80 | (c & 0x3f);
+        } else {
+            /* four bytes */
+            buf[i++] = 0xf0 | (c >>> 18);
+            buf[i++] = 0x80 | (c >>> 12 & 0x3f);
+            buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+            buf[i++] = 0x80 | (c & 0x3f);
+        }
+    }
+
+    return buf;
+};
+
+// Calculate max possible position in utf8 buffer,
+// that will not break sequence. If that's not possible
+// - (very small limits) return max size as is.
+//
+// buf[] - utf8 bytes array
+// max   - length limit (mandatory);
+var utf8border = function(buf, max) {
+    var pos;
+
+    max = max || buf.length;
+    if (max > buf.length) { max = buf.length; }
+
+    // go back from last position, until start of sequence found
+    pos = max-1;
+    while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
+
+    // Fuckup - very small and broken sequence,
+    // return max, because we should return something anyway.
+    if (pos < 0) { return max; }
+
+    // If we came to start of buffer - that means vuffer is too small,
+    // return max too.
+    if (pos === 0) { return max; }
+
+    return (pos + _utf8len[buf[pos]] > max) ? pos : max;
+};
+
+// convert array to string
+var buf2string = function (buf) {
+    var str, i, out, c, c_len;
+    var len = buf.length;
+
+    // Reserve max possible length (2 words per char)
+    // NB: by unknown reasons, Array is significantly faster for
+    //     String.fromCharCode.apply than Uint16Array.
+    var utf16buf = new Array(len*2);
+
+    for (out=0, i=0; i<len;) {
+        c = buf[i++];
+        // quick process ascii
+        if (c < 0x80) { utf16buf[out++] = c; continue; }
+
+        c_len = _utf8len[c];
+        // skip 5 & 6 byte codes
+        if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
+
+        // apply mask on first byte
+        c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
+        // join the rest
+        while (c_len > 1 && i < len) {
+            c = (c << 6) | (buf[i++] & 0x3f);
+            c_len--;
+        }
+
+        // terminated by end of string?
+        if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
+
+        if (c < 0x10000) {
+            utf16buf[out++] = c;
+        } else {
+            c -= 0x10000;
+            utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
+            utf16buf[out++] = 0xdc00 | (c & 0x3ff);
+        }
+    }
+
+    // shrinkBuf(utf16buf, out)
+    if (utf16buf.length !== out) {
+        if(utf16buf.subarray) {
+            utf16buf = utf16buf.subarray(0, out);
+        } else {
+            utf16buf.length = out;
+        }
+    }
+
+    // return String.fromCharCode.apply(null, utf16buf);
+    return utils.applyFromCharCode(utf16buf);
+};
+
+
+// That's all for the pako functions.
+
+
+/**
+ * Transform a javascript string into an array (typed if possible) of bytes,
+ * UTF-8 encoded.
+ * @param {String} str the string to encode
+ * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string.
+ */
+exports.utf8encode = function utf8encode(str) {
+    if (support.nodebuffer) {
+        return nodejsUtils.newBufferFrom(str, "utf-8");
+    }
+
+    return string2buf(str);
+};
+
+
+/**
+ * Transform a bytes array (or a representation) representing an UTF-8 encoded
+ * string into a javascript string.
+ * @param {Array|Uint8Array|Buffer} buf the data de decode
+ * @return {String} the decoded string.
+ */
+exports.utf8decode = function utf8decode(buf) {
+    if (support.nodebuffer) {
+        return utils.transformTo("nodebuffer", buf).toString("utf-8");
+    }
+
+    buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf);
+
+    return buf2string(buf);
+};
+
+/**
+ * A worker to decode utf8 encoded binary chunks into string chunks.
+ * @constructor
+ */
+function Utf8DecodeWorker() {
+    GenericWorker.call(this, "utf-8 decode");
+    // the last bytes if a chunk didn't end with a complete codepoint.
+    this.leftOver = null;
+}
+utils.inherits(Utf8DecodeWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+Utf8DecodeWorker.prototype.processChunk = function (chunk) {
+
+    var data = utils.transformTo(support.uint8array ? "uint8array" : "array", chunk.data);
+
+    // 1st step, re-use what's left of the previous chunk
+    if (this.leftOver && this.leftOver.length) {
+        if(support.uint8array) {
+            var previousData = data;
+            data = new Uint8Array(previousData.length + this.leftOver.length);
+            data.set(this.leftOver, 0);
+            data.set(previousData, this.leftOver.length);
+        } else {
+            data = this.leftOver.concat(data);
+        }
+        this.leftOver = null;
+    }
+
+    var nextBoundary = utf8border(data);
+    var usableData = data;
+    if (nextBoundary !== data.length) {
+        if (support.uint8array) {
+            usableData = data.subarray(0, nextBoundary);
+            this.leftOver = data.subarray(nextBoundary, data.length);
+        } else {
+            usableData = data.slice(0, nextBoundary);
+            this.leftOver = data.slice(nextBoundary, data.length);
+        }
+    }
+
+    this.push({
+        data : exports.utf8decode(usableData),
+        meta : chunk.meta
+    });
+};
+
+/**
+ * @see GenericWorker.flush
+ */
+Utf8DecodeWorker.prototype.flush = function () {
+    if(this.leftOver && this.leftOver.length) {
+        this.push({
+            data : exports.utf8decode(this.leftOver),
+            meta : {}
+        });
+        this.leftOver = null;
+    }
+};
+exports.Utf8DecodeWorker = Utf8DecodeWorker;
+
+/**
+ * A worker to endcode string chunks into utf8 encoded binary chunks.
+ * @constructor
+ */
+function Utf8EncodeWorker() {
+    GenericWorker.call(this, "utf-8 encode");
+}
+utils.inherits(Utf8EncodeWorker, GenericWorker);
+
+/**
+ * @see GenericWorker.processChunk
+ */
+Utf8EncodeWorker.prototype.processChunk = function (chunk) {
+    this.push({
+        data : exports.utf8encode(chunk.data),
+        meta : chunk.meta
+    });
+};
+exports.Utf8EncodeWorker = Utf8EncodeWorker;
+
+},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(require,module,exports){
+'use strict';
+
+var support = require('./support');
+var base64 = require('./base64');
+var nodejsUtils = require('./nodejsUtils');
+var setImmediate = require('set-immediate-shim');
+var external = require("./external");
+
+
+/**
+ * Convert a string that pass as a "binary string": it should represent a byte
+ * array but may have > 255 char codes. Be sure to take only the first byte
+ * and returns the byte array.
+ * @param {String} str the string to transform.
+ * @return {Array|Uint8Array} the string in a binary format.
+ */
+function string2binary(str) {
+    var result = null;
+    if (support.uint8array) {
+      result = new Uint8Array(str.length);
+    } else {
+      result = new Array(str.length);
+    }
+    return stringToArrayLike(str, result);
+}
+
+/**
+ * Create a new blob with the given content and the given type.
+ * @param {String|ArrayBuffer} part the content to put in the blob. DO NOT use
+ * an Uint8Array because the stock browser of android 4 won't accept it (it
+ * will be silently converted to a string, "[object Uint8Array]").
+ *
+ * Use only ONE part to build the blob to avoid a memory leak in IE11 / Edge:
+ * when a large amount of Array is used to create the Blob, the amount of
+ * memory consumed is nearly 100 times the original data amount.
+ *
+ * @param {String} type the mime type of the blob.
+ * @return {Blob} the created blob.
+ */
+exports.newBlob = function(part, type) {
+    exports.checkSupport("blob");
+
+    try {
+        // Blob constructor
+        return new Blob([part], {
+            type: type
+        });
+    }
+    catch (e) {
+
+        try {
+            // deprecated, browser only, old way
+            var Builder = self.BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder;
+            var builder = new Builder();
+            builder.append(part);
+            return builder.getBlob(type);
+        }
+        catch (e) {
+
+            // well, fuck ?!
+            throw new Error("Bug : can't construct the Blob.");
+        }
+    }
+
+
+};
+/**
+ * The identity function.
+ * @param {Object} input the input.
+ * @return {Object} the same input.
+ */
+function identity(input) {
+    return input;
+}
+
+/**
+ * Fill in an array with a string.
+ * @param {String} str the string to use.
+ * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated).
+ * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array.
+ */
+function stringToArrayLike(str, array) {
+    for (var i = 0; i < str.length; ++i) {
+        array[i] = str.charCodeAt(i) & 0xFF;
+    }
+    return array;
+}
+
+/**
+ * An helper for the function arrayLikeToString.
+ * This contains static information and functions that
+ * can be optimized by the browser JIT compiler.
+ */
+var arrayToStringHelper = {
+    /**
+     * Transform an array of int into a string, chunk by chunk.
+     * See the performances notes on arrayLikeToString.
+     * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
+     * @param {String} type the type of the array.
+     * @param {Integer} chunk the chunk size.
+     * @return {String} the resulting string.
+     * @throws Error if the chunk is too big for the stack.
+     */
+    stringifyByChunk: function(array, type, chunk) {
+        var result = [], k = 0, len = array.length;
+        // shortcut
+        if (len <= chunk) {
+            return String.fromCharCode.apply(null, array);
+        }
+        while (k < len) {
+            if (type === "array" || type === "nodebuffer") {
+                result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len))));
+            }
+            else {
+                result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len))));
+            }
+            k += chunk;
+        }
+        return result.join("");
+    },
+    /**
+     * Call String.fromCharCode on every item in the array.
+     * This is the naive implementation, which generate A LOT of intermediate string.
+     * This should be used when everything else fail.
+     * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
+     * @return {String} the result.
+     */
+    stringifyByChar: function(array){
+        var resultStr = "";
+        for(var i = 0; i < array.length; i++) {
+            resultStr += String.fromCharCode(array[i]);
+        }
+        return resultStr;
+    },
+    applyCanBeUsed : {
+        /**
+         * true if the browser accepts to use String.fromCharCode on Uint8Array
+         */
+        uint8array : (function () {
+            try {
+                return support.uint8array && String.fromCharCode.apply(null, new Uint8Array(1)).length === 1;
+            } catch (e) {
+                return false;
+            }
+        })(),
+        /**
+         * true if the browser accepts to use String.fromCharCode on nodejs Buffer.
+         */
+        nodebuffer : (function () {
+            try {
+                return support.nodebuffer && String.fromCharCode.apply(null, nodejsUtils.allocBuffer(1)).length === 1;
+            } catch (e) {
+                return false;
+            }
+        })()
+    }
+};
+
+/**
+ * Transform an array-like object to a string.
+ * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform.
+ * @return {String} the result.
+ */
+function arrayLikeToString(array) {
+    // Performances notes :
+    // --------------------
+    // String.fromCharCode.apply(null, array) is the fastest, see
+    // see http://jsperf.com/converting-a-uint8array-to-a-string/2
+    // but the stack is limited (and we can get huge arrays !).
+    //
+    // result += String.fromCharCode(array[i]); generate too many strings !
+    //
+    // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2
+    // TODO : we now have workers that split the work. Do we still need that ?
+    var chunk = 65536,
+        type = exports.getTypeOf(array),
+        canUseApply = true;
+    if (type === "uint8array") {
+        canUseApply = arrayToStringHelper.applyCanBeUsed.uint8array;
+    } else if (type === "nodebuffer") {
+        canUseApply = arrayToStringHelper.applyCanBeUsed.nodebuffer;
+    }
+
+    if (canUseApply) {
+        while (chunk > 1) {
+            try {
+                return arrayToStringHelper.stringifyByChunk(array, type, chunk);
+            } catch (e) {
+                chunk = Math.floor(chunk / 2);
+            }
+        }
+    }
+
+    // no apply or chunk error : slow and painful algorithm
+    // default browser on android 4.*
+    return arrayToStringHelper.stringifyByChar(array);
+}
+
+exports.applyFromCharCode = arrayLikeToString;
+
+
+/**
+ * Copy the data from an array-like to an other array-like.
+ * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array.
+ * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated.
+ * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array.
+ */
+function arrayLikeToArrayLike(arrayFrom, arrayTo) {
+    for (var i = 0; i < arrayFrom.length; i++) {
+        arrayTo[i] = arrayFrom[i];
+    }
+    return arrayTo;
+}
+
+// a matrix containing functions to transform everything into everything.
+var transform = {};
+
+// string to ?
+transform["string"] = {
+    "string": identity,
+    "array": function(input) {
+        return stringToArrayLike(input, new Array(input.length));
+    },
+    "arraybuffer": function(input) {
+        return transform["string"]["uint8array"](input).buffer;
+    },
+    "uint8array": function(input) {
+        return stringToArrayLike(input, new Uint8Array(input.length));
+    },
+    "nodebuffer": function(input) {
+        return stringToArrayLike(input, nodejsUtils.allocBuffer(input.length));
+    }
+};
+
+// array to ?
+transform["array"] = {
+    "string": arrayLikeToString,
+    "array": identity,
+    "arraybuffer": function(input) {
+        return (new Uint8Array(input)).buffer;
+    },
+    "uint8array": function(input) {
+        return new Uint8Array(input);
+    },
+    "nodebuffer": function(input) {
+        return nodejsUtils.newBufferFrom(input);
+    }
+};
+
+// arraybuffer to ?
+transform["arraybuffer"] = {
+    "string": function(input) {
+        return arrayLikeToString(new Uint8Array(input));
+    },
+    "array": function(input) {
+        return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength));
+    },
+    "arraybuffer": identity,
+    "uint8array": function(input) {
+        return new Uint8Array(input);
+    },
+    "nodebuffer": function(input) {
+        return nodejsUtils.newBufferFrom(new Uint8Array(input));
+    }
+};
+
+// uint8array to ?
+transform["uint8array"] = {
+    "string": arrayLikeToString,
+    "array": function(input) {
+        return arrayLikeToArrayLike(input, new Array(input.length));
+    },
+    "arraybuffer": function(input) {
+        return input.buffer;
+    },
+    "uint8array": identity,
+    "nodebuffer": function(input) {
+        return nodejsUtils.newBufferFrom(input);
+    }
+};
+
+// nodebuffer to ?
+transform["nodebuffer"] = {
+    "string": arrayLikeToString,
+    "array": function(input) {
+        return arrayLikeToArrayLike(input, new Array(input.length));
+    },
+    "arraybuffer": function(input) {
+        return transform["nodebuffer"]["uint8array"](input).buffer;
+    },
+    "uint8array": function(input) {
+        return arrayLikeToArrayLike(input, new Uint8Array(input.length));
+    },
+    "nodebuffer": identity
+};
+
+/**
+ * Transform an input into any type.
+ * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer.
+ * If no output type is specified, the unmodified input will be returned.
+ * @param {String} outputType the output type.
+ * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert.
+ * @throws {Error} an Error if the browser doesn't support the requested output type.
+ */
+exports.transformTo = function(outputType, input) {
+    if (!input) {
+        // undefined, null, etc
+        // an empty string won't harm.
+        input = "";
+    }
+    if (!outputType) {
+        return input;
+    }
+    exports.checkSupport(outputType);
+    var inputType = exports.getTypeOf(input);
+    var result = transform[inputType][outputType](input);
+    return result;
+};
+
+/**
+ * Return the type of the input.
+ * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer.
+ * @param {Object} input the input to identify.
+ * @return {String} the (lowercase) type of the input.
+ */
+exports.getTypeOf = function(input) {
+    if (typeof input === "string") {
+        return "string";
+    }
+    if (Object.prototype.toString.call(input) === "[object Array]") {
+        return "array";
+    }
+    if (support.nodebuffer && nodejsUtils.isBuffer(input)) {
+        return "nodebuffer";
+    }
+    if (support.uint8array && input instanceof Uint8Array) {
+        return "uint8array";
+    }
+    if (support.arraybuffer && input instanceof ArrayBuffer) {
+        return "arraybuffer";
+    }
+};
+
+/**
+ * Throw an exception if the type is not supported.
+ * @param {String} type the type to check.
+ * @throws {Error} an Error if the browser doesn't support the requested type.
+ */
+exports.checkSupport = function(type) {
+    var supported = support[type.toLowerCase()];
+    if (!supported) {
+        throw new Error(type + " is not supported by this platform");
+    }
+};
+
+exports.MAX_VALUE_16BITS = 65535;
+exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
+
+/**
+ * Prettify a string read as binary.
+ * @param {string} str the string to prettify.
+ * @return {string} a pretty string.
+ */
+exports.pretty = function(str) {
+    var res = '',
+        code, i;
+    for (i = 0; i < (str || "").length; i++) {
+        code = str.charCodeAt(i);
+        res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase();
+    }
+    return res;
+};
+
+/**
+ * Defer the call of a function.
+ * @param {Function} callback the function to call asynchronously.
+ * @param {Array} args the arguments to give to the callback.
+ */
+exports.delay = function(callback, args, self) {
+    setImmediate(function () {
+        callback.apply(self || null, args || []);
+    });
+};
+
+/**
+ * Extends a prototype with an other, without calling a constructor with
+ * side effects. Inspired by nodejs' `utils.inherits`
+ * @param {Function} ctor the constructor to augment
+ * @param {Function} superCtor the parent constructor to use
+ */
+exports.inherits = function (ctor, superCtor) {
+    var Obj = function() {};
+    Obj.prototype = superCtor.prototype;
+    ctor.prototype = new Obj();
+};
+
+/**
+ * Merge the objects passed as parameters into a new one.
+ * @private
+ * @param {...Object} var_args All objects to merge.
+ * @return {Object} a new object with the data of the others.
+ */
+exports.extend = function() {
+    var result = {}, i, attr;
+    for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers
+        for (attr in arguments[i]) {
+            if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") {
+                result[attr] = arguments[i][attr];
+            }
+        }
+    }
+    return result;
+};
+
+/**
+ * Transform arbitrary content into a Promise.
+ * @param {String} name a name for the content being processed.
+ * @param {Object} inputData the content to process.
+ * @param {Boolean} isBinary true if the content is not an unicode string
+ * @param {Boolean} isOptimizedBinaryString true if the string content only has one byte per character.
+ * @param {Boolean} isBase64 true if the string content is encoded with base64.
+ * @return {Promise} a promise in a format usable by JSZip.
+ */
+exports.prepareContent = function(name, inputData, isBinary, isOptimizedBinaryString, isBase64) {
+
+    // if inputData is already a promise, this flatten it.
+    var promise = external.Promise.resolve(inputData).then(function(data) {
+        
+        
+        var isBlob = support.blob && (data instanceof Blob || ['[object File]', '[object Blob]'].indexOf(Object.prototype.toString.call(data)) !== -1);
+
+        if (isBlob && typeof FileReader !== "undefined") {
+            return new external.Promise(function (resolve, reject) {
+                var reader = new FileReader();
+
+                reader.onload = function(e) {
+                    resolve(e.target.result);
+                };
+                reader.onerror = function(e) {
+                    reject(e.target.error);
+                };
+                reader.readAsArrayBuffer(data);
+            });
+        } else {
+            return data;
+        }
+    });
+
+    return promise.then(function(data) {
+        var dataType = exports.getTypeOf(data);
+
+        if (!dataType) {
+            return external.Promise.reject(
+                new Error("Can't read the data of '" + name + "'. Is it " +
+                          "in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?")
+            );
+        }
+        // special case : it's way easier to work with Uint8Array than with ArrayBuffer
+        if (dataType === "arraybuffer") {
+            data = exports.transformTo("uint8array", data);
+        } else if (dataType === "string") {
+            if (isBase64) {
+                data = base64.decode(data);
+            }
+            else if (isBinary) {
+                // optimizedBinaryString === true means that the file has already been filtered with a 0xFF mask
+                if (isOptimizedBinaryString !== true) {
+                    // this is a string, not in a base64 format.
+                    // Be sure that this is a correct "binary string"
+                    data = string2binary(data);
+                }
+            }
+        }
+        return data;
+    });
+};
+
+},{"./base64":1,"./external":6,"./nodejsUtils":14,"./support":30,"set-immediate-shim":54}],33:[function(require,module,exports){
+'use strict';
+var readerFor = require('./reader/readerFor');
+var utils = require('./utils');
+var sig = require('./signature');
+var ZipEntry = require('./zipEntry');
+var utf8 = require('./utf8');
+var support = require('./support');
+//  class ZipEntries {{{
+/**
+ * All the entries in the zip file.
+ * @constructor
+ * @param {Object} loadOptions Options for loading the stream.
+ */
+function ZipEntries(loadOptions) {
+    this.files = [];
+    this.loadOptions = loadOptions;
+}
+ZipEntries.prototype = {
+    /**
+     * Check that the reader is on the specified signature.
+     * @param {string} expectedSignature the expected signature.
+     * @throws {Error} if it is an other signature.
+     */
+    checkSignature: function(expectedSignature) {
+        if (!this.reader.readAndCheckSignature(expectedSignature)) {
+            this.reader.index -= 4;
+            var signature = this.reader.readString(4);
+            throw new Error("Corrupted zip or bug: unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")");
+        }
+    },
+    /**
+     * Check if the given signature is at the given index.
+     * @param {number} askedIndex the index to check.
+     * @param {string} expectedSignature the signature to expect.
+     * @return {boolean} true if the signature is here, false otherwise.
+     */
+    isSignature: function(askedIndex, expectedSignature) {
+        var currentIndex = this.reader.index;
+        this.reader.setIndex(askedIndex);
+        var signature = this.reader.readString(4);
+        var result = signature === expectedSignature;
+        this.reader.setIndex(currentIndex);
+        return result;
+    },
+    /**
+     * Read the end of the central directory.
+     */
+    readBlockEndOfCentral: function() {
+        this.diskNumber = this.reader.readInt(2);
+        this.diskWithCentralDirStart = this.reader.readInt(2);
+        this.centralDirRecordsOnThisDisk = this.reader.readInt(2);
+        this.centralDirRecords = this.reader.readInt(2);
+        this.centralDirSize = this.reader.readInt(4);
+        this.centralDirOffset = this.reader.readInt(4);
+
+        this.zipCommentLength = this.reader.readInt(2);
+        // warning : the encoding depends of the system locale
+        // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded.
+        // On a windows machine, this field is encoded with the localized windows code page.
+        var zipComment = this.reader.readData(this.zipCommentLength);
+        var decodeParamType = support.uint8array ? "uint8array" : "array";
+        // To get consistent behavior with the generation part, we will assume that
+        // this is utf8 encoded unless specified otherwise.
+        var decodeContent = utils.transformTo(decodeParamType, zipComment);
+        this.zipComment = this.loadOptions.decodeFileName(decodeContent);
+    },
+    /**
+     * Read the end of the Zip 64 central directory.
+     * Not merged with the method readEndOfCentral :
+     * The end of central can coexist with its Zip64 brother,
+     * I don't want to read the wrong number of bytes !
+     */
+    readBlockZip64EndOfCentral: function() {
+        this.zip64EndOfCentralSize = this.reader.readInt(8);
+        this.reader.skip(4);
+        // this.versionMadeBy = this.reader.readString(2);
+        // this.versionNeeded = this.reader.readInt(2);
+        this.diskNumber = this.reader.readInt(4);
+        this.diskWithCentralDirStart = this.reader.readInt(4);
+        this.centralDirRecordsOnThisDisk = this.reader.readInt(8);
+        this.centralDirRecords = this.reader.readInt(8);
+        this.centralDirSize = this.reader.readInt(8);
+        this.centralDirOffset = this.reader.readInt(8);
+
+        this.zip64ExtensibleData = {};
+        var extraDataSize = this.zip64EndOfCentralSize - 44,
+            index = 0,
+            extraFieldId,
+            extraFieldLength,
+            extraFieldValue;
+        while (index < extraDataSize) {
+            extraFieldId = this.reader.readInt(2);
+            extraFieldLength = this.reader.readInt(4);
+            extraFieldValue = this.reader.readData(extraFieldLength);
+            this.zip64ExtensibleData[extraFieldId] = {
+                id: extraFieldId,
+                length: extraFieldLength,
+                value: extraFieldValue
+            };
+        }
+    },
+    /**
+     * Read the end of the Zip 64 central directory locator.
+     */
+    readBlockZip64EndOfCentralLocator: function() {
+        this.diskWithZip64CentralDirStart = this.reader.readInt(4);
+        this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);
+        this.disksCount = this.reader.readInt(4);
+        if (this.disksCount > 1) {
+            throw new Error("Multi-volumes zip are not supported");
+        }
+    },
+    /**
+     * Read the local files, based on the offset read in the central part.
+     */
+    readLocalFiles: function() {
+        var i, file;
+        for (i = 0; i < this.files.length; i++) {
+            file = this.files[i];
+            this.reader.setIndex(file.localHeaderOffset);
+            this.checkSignature(sig.LOCAL_FILE_HEADER);
+            file.readLocalPart(this.reader);
+            file.handleUTF8();
+            file.processAttributes();
+        }
+    },
+    /**
+     * Read the central directory.
+     */
+    readCentralDir: function() {
+        var file;
+
+        this.reader.setIndex(this.centralDirOffset);
+        while (this.reader.readAndCheckSignature(sig.CENTRAL_FILE_HEADER)) {
+            file = new ZipEntry({
+                zip64: this.zip64
+            }, this.loadOptions);
+            file.readCentralPart(this.reader);
+            this.files.push(file);
+        }
+
+        if (this.centralDirRecords !== this.files.length) {
+            if (this.centralDirRecords !== 0 && this.files.length === 0) {
+                // We expected some records but couldn't find ANY.
+                // This is really suspicious, as if something went wrong.
+                throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length);
+            } else {
+                // We found some records but not all.
+                // Something is wrong but we got something for the user: no error here.
+                // console.warn("expected", this.centralDirRecords, "records in central dir, got", this.files.length);
+            }
+        }
+    },
+    /**
+     * Read the end of central directory.
+     */
+    readEndOfCentral: function() {
+        var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END);
+        if (offset < 0) {
+            // Check if the content is a truncated zip or complete garbage.
+            // A "LOCAL_FILE_HEADER" is not required at the beginning (auto
+            // extractible zip for example) but it can give a good hint.
+            // If an ajax request was used without responseType, we will also
+            // get unreadable data.
+            var isGarbage = !this.isSignature(0, sig.LOCAL_FILE_HEADER);
+
+            if (isGarbage) {
+                throw new Error("Can't find end of central directory : is this a zip file ? " +
+                                "If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html");
+            } else {
+                throw new Error("Corrupted zip: can't find end of central directory");
+            }
+
+        }
+        this.reader.setIndex(offset);
+        var endOfCentralDirOffset = offset;
+        this.checkSignature(sig.CENTRAL_DIRECTORY_END);
+        this.readBlockEndOfCentral();
+
+
+        /* extract from the zip spec :
+            4)  If one of the fields in the end of central directory
+                record is too small to hold required data, the field
+                should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
+                ZIP64 format record should be created.
+            5)  The end of central directory record and the
+                Zip64 end of central directory locator record must
+                reside on the same disk when splitting or spanning
+                an archive.
+         */
+        if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) {
+            this.zip64 = true;
+
+            /*
+            Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from
+            the zip file can fit into a 32bits integer. This cannot be solved : JavaScript represents
+            all numbers as 64-bit double precision IEEE 754 floating point numbers.
+            So, we have 53bits for integers and bitwise operations treat everything as 32bits.
+            see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
+            and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
+            */
+
+            // should look for a zip64 EOCD locator
+            offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
+            if (offset < 0) {
+                throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");
+            }
+            this.reader.setIndex(offset);
+            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
+            this.readBlockZip64EndOfCentralLocator();
+
+            // now the zip64 EOCD record
+            if (!this.isSignature(this.relativeOffsetEndOfZip64CentralDir, sig.ZIP64_CENTRAL_DIRECTORY_END)) {
+                // console.warn("ZIP64 end of central directory not where expected.");
+                this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
+                if (this.relativeOffsetEndOfZip64CentralDir < 0) {
+                    throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");
+                }
+            }
+            this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);
+            this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END);
+            this.readBlockZip64EndOfCentral();
+        }
+
+        var expectedEndOfCentralDirOffset = this.centralDirOffset + this.centralDirSize;
+        if (this.zip64) {
+            expectedEndOfCentralDirOffset += 20; // end of central dir 64 locator
+            expectedEndOfCentralDirOffset += 12 /* should not include the leading 12 bytes */ + this.zip64EndOfCentralSize;
+        }
+
+        var extraBytes = endOfCentralDirOffset - expectedEndOfCentralDirOffset;
+
+        if (extraBytes > 0) {
+            // console.warn(extraBytes, "extra bytes at beginning or within zipfile");
+            if (this.isSignature(endOfCentralDirOffset, sig.CENTRAL_FILE_HEADER)) {
+                // The offsets seem wrong, but we have something at the specified offset.
+                // So… we keep it.
+            } else {
+                // the offset is wrong, update the "zero" of the reader
+                // this happens if data has been prepended (crx files for example)
+                this.reader.zero = extraBytes;
+            }
+        } else if (extraBytes < 0) {
+            throw new Error("Corrupted zip: missing " + Math.abs(extraBytes) + " bytes.");
+        }
+    },
+    prepareReader: function(data) {
+        this.reader = readerFor(data);
+    },
+    /**
+     * Read a zip file and create ZipEntries.
+     * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file.
+     */
+    load: function(data) {
+        this.prepareReader(data);
+        this.readEndOfCentral();
+        this.readCentralDir();
+        this.readLocalFiles();
+    }
+};
+// }}} end of ZipEntries
+module.exports = ZipEntries;
+
+},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utf8":31,"./utils":32,"./zipEntry":34}],34:[function(require,module,exports){
+'use strict';
+var readerFor = require('./reader/readerFor');
+var utils = require('./utils');
+var CompressedObject = require('./compressedObject');
+var crc32fn = require('./crc32');
+var utf8 = require('./utf8');
+var compressions = require('./compressions');
+var support = require('./support');
+
+var MADE_BY_DOS = 0x00;
+var MADE_BY_UNIX = 0x03;
+
+/**
+ * Find a compression registered in JSZip.
+ * @param {string} compressionMethod the method magic to find.
+ * @return {Object|null} the JSZip compression object, null if none found.
+ */
+var findCompression = function(compressionMethod) {
+    for (var method in compressions) {
+        if (!compressions.hasOwnProperty(method)) {
+            continue;
+        }
+        if (compressions[method].magic === compressionMethod) {
+            return compressions[method];
+        }
+    }
+    return null;
+};
+
+// class ZipEntry {{{
+/**
+ * An entry in the zip file.
+ * @constructor
+ * @param {Object} options Options of the current file.
+ * @param {Object} loadOptions Options for loading the stream.
+ */
+function ZipEntry(options, loadOptions) {
+    this.options = options;
+    this.loadOptions = loadOptions;
+}
+ZipEntry.prototype = {
+    /**
+     * say if the file is encrypted.
+     * @return {boolean} true if the file is encrypted, false otherwise.
+     */
+    isEncrypted: function() {
+        // bit 1 is set
+        return (this.bitFlag & 0x0001) === 0x0001;
+    },
+    /**
+     * say if the file has utf-8 filename/comment.
+     * @return {boolean} true if the filename/comment is in utf-8, false otherwise.
+     */
+    useUTF8: function() {
+        // bit 11 is set
+        return (this.bitFlag & 0x0800) === 0x0800;
+    },
+    /**
+     * Read the local part of a zip file and add the info in this object.
+     * @param {DataReader} reader the reader to use.
+     */
+    readLocalPart: function(reader) {
+        var compression, localExtraFieldsLength;
+
+        // we already know everything from the central dir !
+        // If the central dir data are false, we are doomed.
+        // On the bright side, the local part is scary  : zip64, data descriptors, both, etc.
+        // The less data we get here, the more reliable this should be.
+        // Let's skip the whole header and dash to the data !
+        reader.skip(22);
+        // in some zip created on windows, the filename stored in the central dir contains \ instead of /.
+        // Strangely, the filename here is OK.
+        // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
+        // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
+        // Search "unzip mismatching "local" filename continuing with "central" filename version" on
+        // the internet.
+        //
+        // I think I see the logic here : the central directory is used to display
+        // content and the local directory is used to extract the files. Mixing / and \
+        // may be used to display \ to windows users and use / when extracting the files.
+        // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
+        this.fileNameLength = reader.readInt(2);
+        localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir
+        // the fileName is stored as binary data, the handleUTF8 method will take care of the encoding.
+        this.fileName = reader.readData(this.fileNameLength);
+        reader.skip(localExtraFieldsLength);
+
+        if (this.compressedSize === -1 || this.uncompressedSize === -1) {
+            throw new Error("Bug or corrupted zip : didn't get enough information from the central directory " + "(compressedSize === -1 || uncompressedSize === -1)");
+        }
+
+        compression = findCompression(this.compressionMethod);
+        if (compression === null) { // no compression found
+            throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + utils.transformTo("string", this.fileName) + ")");
+        }
+        this.decompressed = new CompressedObject(this.compressedSize, this.uncompressedSize, this.crc32, compression, reader.readData(this.compressedSize));
+    },
+
+    /**
+     * Read the central part of a zip file and add the info in this object.
+     * @param {DataReader} reader the reader to use.
+     */
+    readCentralPart: function(reader) {
+        this.versionMadeBy = reader.readInt(2);
+        reader.skip(2);
+        // this.versionNeeded = reader.readInt(2);
+        this.bitFlag = reader.readInt(2);
+        this.compressionMethod = reader.readString(2);
+        this.date = reader.readDate();
+        this.crc32 = reader.readInt(4);
+        this.compressedSize = reader.readInt(4);
+        this.uncompressedSize = reader.readInt(4);
+        var fileNameLength = reader.readInt(2);
+        this.extraFieldsLength = reader.readInt(2);
+        this.fileCommentLength = reader.readInt(2);
+        this.diskNumberStart = reader.readInt(2);
+        this.internalFileAttributes = reader.readInt(2);
+        this.externalFileAttributes = reader.readInt(4);
+        this.localHeaderOffset = reader.readInt(4);
+
+        if (this.isEncrypted()) {
+            throw new Error("Encrypted zip are not supported");
+        }
+
+        // will be read in the local part, see the comments there
+        reader.skip(fileNameLength);
+        this.readExtraFields(reader);
+        this.parseZIP64ExtraField(reader);
+        this.fileComment = reader.readData(this.fileCommentLength);
+    },
+
+    /**
+     * Parse the external file attributes and get the unix/dos permissions.
+     */
+    processAttributes: function () {
+        this.unixPermissions = null;
+        this.dosPermissions = null;
+        var madeBy = this.versionMadeBy >> 8;
+
+        // Check if we have the DOS directory flag set.
+        // We look for it in the DOS and UNIX permissions
+        // but some unknown platform could set it as a compatibility flag.
+        this.dir = this.externalFileAttributes & 0x0010 ? true : false;
+
+        if(madeBy === MADE_BY_DOS) {
+            // first 6 bits (0 to 5)
+            this.dosPermissions = this.externalFileAttributes & 0x3F;
+        }
+
+        if(madeBy === MADE_BY_UNIX) {
+            this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF;
+            // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8);
+        }
+
+        // fail safe : if the name ends with a / it probably means a folder
+        if (!this.dir && this.fileNameStr.slice(-1) === '/') {
+            this.dir = true;
+        }
+    },
+
+    /**
+     * Parse the ZIP64 extra field and merge the info in the current ZipEntry.
+     * @param {DataReader} reader the reader to use.
+     */
+    parseZIP64ExtraField: function(reader) {
+
+        if (!this.extraFields[0x0001]) {
+            return;
+        }
+
+        // should be something, preparing the extra reader
+        var extraReader = readerFor(this.extraFields[0x0001].value);
+
+        // I really hope that these 64bits integer can fit in 32 bits integer, because js
+        // won't let us have more.
+        if (this.uncompressedSize === utils.MAX_VALUE_32BITS) {
+            this.uncompressedSize = extraReader.readInt(8);
+        }
+        if (this.compressedSize === utils.MAX_VALUE_32BITS) {
+            this.compressedSize = extraReader.readInt(8);
+        }
+        if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) {
+            this.localHeaderOffset = extraReader.readInt(8);
+        }
+        if (this.diskNumberStart === utils.MAX_VALUE_32BITS) {
+            this.diskNumberStart = extraReader.readInt(4);
+        }
+    },
+    /**
+     * Read the central part of a zip file and add the info in this object.
+     * @param {DataReader} reader the reader to use.
+     */
+    readExtraFields: function(reader) {
+        var end = reader.index + this.extraFieldsLength,
+            extraFieldId,
+            extraFieldLength,
+            extraFieldValue;
+
+        if (!this.extraFields) {
+            this.extraFields = {};
+        }
+
+        while (reader.index + 4 < end) {
+            extraFieldId = reader.readInt(2);
+            extraFieldLength = reader.readInt(2);
+            extraFieldValue = reader.readData(extraFieldLength);
+
+            this.extraFields[extraFieldId] = {
+                id: extraFieldId,
+                length: extraFieldLength,
+                value: extraFieldValue
+            };
+        }
+
+        reader.setIndex(end);
+    },
+    /**
+     * Apply an UTF8 transformation if needed.
+     */
+    handleUTF8: function() {
+        var decodeParamType = support.uint8array ? "uint8array" : "array";
+        if (this.useUTF8()) {
+            this.fileNameStr = utf8.utf8decode(this.fileName);
+            this.fileCommentStr = utf8.utf8decode(this.fileComment);
+        } else {
+            var upath = this.findExtraFieldUnicodePath();
+            if (upath !== null) {
+                this.fileNameStr = upath;
+            } else {
+                // ASCII text or unsupported code page
+                var fileNameByteArray =  utils.transformTo(decodeParamType, this.fileName);
+                this.fileNameStr = this.loadOptions.decodeFileName(fileNameByteArray);
+            }
+
+            var ucomment = this.findExtraFieldUnicodeComment();
+            if (ucomment !== null) {
+                this.fileCommentStr = ucomment;
+            } else {
+                // ASCII text or unsupported code page
+                var commentByteArray =  utils.transformTo(decodeParamType, this.fileComment);
+                this.fileCommentStr = this.loadOptions.decodeFileName(commentByteArray);
+            }
+        }
+    },
+
+    /**
+     * Find the unicode path declared in the extra field, if any.
+     * @return {String} the unicode path, null otherwise.
+     */
+    findExtraFieldUnicodePath: function() {
+        var upathField = this.extraFields[0x7075];
+        if (upathField) {
+            var extraReader = readerFor(upathField.value);
+
+            // wrong version
+            if (extraReader.readInt(1) !== 1) {
+                return null;
+            }
+
+            // the crc of the filename changed, this field is out of date.
+            if (crc32fn(this.fileName) !== extraReader.readInt(4)) {
+                return null;
+            }
+
+            return utf8.utf8decode(extraReader.readData(upathField.length - 5));
+        }
+        return null;
+    },
+
+    /**
+     * Find the unicode comment declared in the extra field, if any.
+     * @return {String} the unicode comment, null otherwise.
+     */
+    findExtraFieldUnicodeComment: function() {
+        var ucommentField = this.extraFields[0x6375];
+        if (ucommentField) {
+            var extraReader = readerFor(ucommentField.value);
+
+            // wrong version
+            if (extraReader.readInt(1) !== 1) {
+                return null;
+            }
+
+            // the crc of the comment changed, this field is out of date.
+            if (crc32fn(this.fileComment) !== extraReader.readInt(4)) {
+                return null;
+            }
+
+            return utf8.utf8decode(extraReader.readData(ucommentField.length - 5));
+        }
+        return null;
+    }
+};
+module.exports = ZipEntry;
+
+},{"./compressedObject":2,"./compressions":3,"./crc32":4,"./reader/readerFor":22,"./support":30,"./utf8":31,"./utils":32}],35:[function(require,module,exports){
+'use strict';
+
+var StreamHelper = require('./stream/StreamHelper');
+var DataWorker = require('./stream/DataWorker');
+var utf8 = require('./utf8');
+var CompressedObject = require('./compressedObject');
+var GenericWorker = require('./stream/GenericWorker');
+
+/**
+ * A simple object representing a file in the zip file.
+ * @constructor
+ * @param {string} name the name of the file
+ * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data
+ * @param {Object} options the options of the file
+ */
+var ZipObject = function(name, data, options) {
+    this.name = name;
+    this.dir = options.dir;
+    this.date = options.date;
+    this.comment = options.comment;
+    this.unixPermissions = options.unixPermissions;
+    this.dosPermissions = options.dosPermissions;
+
+    this._data = data;
+    this._dataBinary = options.binary;
+    // keep only the compression
+    this.options = {
+        compression : options.compression,
+        compressionOptions : options.compressionOptions
+    };
+};
+
+ZipObject.prototype = {
+    /**
+     * Create an internal stream for the content of this object.
+     * @param {String} type the type of each chunk.
+     * @return StreamHelper the stream.
+     */
+    internalStream: function (type) {
+        var result = null, outputType = "string";
+        try {
+            if (!type) {
+                throw new Error("No output type specified.");
+            }
+            outputType = type.toLowerCase();
+            var askUnicodeString = outputType === "string" || outputType === "text";
+            if (outputType === "binarystring" || outputType === "text") {
+                outputType = "string";
+            }
+            result = this._decompressWorker();
+
+            var isUnicodeString = !this._dataBinary;
+
+            if (isUnicodeString && !askUnicodeString) {
+                result = result.pipe(new utf8.Utf8EncodeWorker());
+            }
+            if (!isUnicodeString && askUnicodeString) {
+                result = result.pipe(new utf8.Utf8DecodeWorker());
+            }
+        } catch (e) {
+            result = new GenericWorker("error");
+            result.error(e);
+        }
+
+        return new StreamHelper(result, outputType, "");
+    },
+
+    /**
+     * Prepare the content in the asked type.
+     * @param {String} type the type of the result.
+     * @param {Function} onUpdate a function to call on each internal update.
+     * @return Promise the promise of the result.
+     */
+    async: function (type, onUpdate) {
+        return this.internalStream(type).accumulate(onUpdate);
+    },
+
+    /**
+     * Prepare the content as a nodejs stream.
+     * @param {String} type the type of each chunk.
+     * @param {Function} onUpdate a function to call on each internal update.
+     * @return Stream the stream.
+     */
+    nodeStream: function (type, onUpdate) {
+        return this.internalStream(type || "nodebuffer").toNodejsStream(onUpdate);
+    },
+
+    /**
+     * Return a worker for the compressed content.
+     * @private
+     * @param {Object} compression the compression object to use.
+     * @param {Object} compressionOptions the options to use when compressing.
+     * @return Worker the worker.
+     */
+    _compressWorker: function (compression, compressionOptions) {
+        if (
+            this._data instanceof CompressedObject &&
+            this._data.compression.magic === compression.magic
+        ) {
+            return this._data.getCompressedWorker();
+        } else {
+            var result = this._decompressWorker();
+            if(!this._dataBinary) {
+                result = result.pipe(new utf8.Utf8EncodeWorker());
+            }
+            return CompressedObject.createWorkerFrom(result, compression, compressionOptions);
+        }
+    },
+    /**
+     * Return a worker for the decompressed content.
+     * @private
+     * @return Worker the worker.
+     */
+    _decompressWorker : function () {
+        if (this._data instanceof CompressedObject) {
+            return this._data.getContentWorker();
+        } else if (this._data instanceof GenericWorker) {
+            return this._data;
+        } else {
+            return new DataWorker(this._data);
+        }
+    }
+};
+
+var removedMethods = ["asText", "asBinary", "asNodeBuffer", "asUint8Array", "asArrayBuffer"];
+var removedFn = function () {
+    throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.");
+};
+
+for(var i = 0; i < removedMethods.length; i++) {
+    ZipObject.prototype[removedMethods[i]] = removedFn;
+}
+module.exports = ZipObject;
+
+},{"./compressedObject":2,"./stream/DataWorker":27,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31}],36:[function(require,module,exports){
+(function (global){
+'use strict';
+var Mutation = global.MutationObserver || global.WebKitMutationObserver;
+
+var scheduleDrain;
+
+{
+  if (Mutation) {
+    var called = 0;
+    var observer = new Mutation(nextTick);
+    var element = global.document.createTextNode('');
+    observer.observe(element, {
+      characterData: true
+    });
+    scheduleDrain = function () {
+      element.data = (called = ++called % 2);
+    };
+  } else if (!global.setImmediate && typeof global.MessageChannel !== 'undefined') {
+    var channel = new global.MessageChannel();
+    channel.port1.onmessage = nextTick;
+    scheduleDrain = function () {
+      channel.port2.postMessage(0);
+    };
+  } else if ('document' in global && 'onreadystatechange' in global.document.createElement('script')) {
+    scheduleDrain = function () {
+
+      // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
+      // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
+      var scriptEl = global.document.createElement('script');
+      scriptEl.onreadystatechange = function () {
+        nextTick();
+
+        scriptEl.onreadystatechange = null;
+        scriptEl.parentNode.removeChild(scriptEl);
+        scriptEl = null;
+      };
+      global.document.documentElement.appendChild(scriptEl);
+    };
+  } else {
+    scheduleDrain = function () {
+      setTimeout(nextTick, 0);
+    };
+  }
+}
+
+var draining;
+var queue = [];
+//named nextTick for less confusing stack traces
+function nextTick() {
+  draining = true;
+  var i, oldQueue;
+  var len = queue.length;
+  while (len) {
+    oldQueue = queue;
+    queue = [];
+    i = -1;
+    while (++i < len) {
+      oldQueue[i]();
+    }
+    len = queue.length;
+  }
+  draining = false;
+}
+
+module.exports = immediate;
+function immediate(task) {
+  if (queue.push(task) === 1 && !draining) {
+    scheduleDrain();
+  }
+}
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}],37:[function(require,module,exports){
+'use strict';
+var immediate = require('immediate');
+
+/* istanbul ignore next */
+function INTERNAL() {}
+
+var handlers = {};
+
+var REJECTED = ['REJECTED'];
+var FULFILLED = ['FULFILLED'];
+var PENDING = ['PENDING'];
+
+module.exports = Promise;
+
+function Promise(resolver) {
+  if (typeof resolver !== 'function') {
+    throw new TypeError('resolver must be a function');
+  }
+  this.state = PENDING;
+  this.queue = [];
+  this.outcome = void 0;
+  if (resolver !== INTERNAL) {
+    safelyResolveThenable(this, resolver);
+  }
+}
+
+Promise.prototype["finally"] = function (callback) {
+  if (typeof callback !== 'function') {
+    return this;
+  }
+  var p = this.constructor;
+  return this.then(resolve, reject);
+
+  function resolve(value) {
+    function yes () {
+      return value;
+    }
+    return p.resolve(callback()).then(yes);
+  }
+  function reject(reason) {
+    function no () {
+      throw reason;
+    }
+    return p.resolve(callback()).then(no);
+  }
+};
+Promise.prototype["catch"] = function (onRejected) {
+  return this.then(null, onRejected);
+};
+Promise.prototype.then = function (onFulfilled, onRejected) {
+  if (typeof onFulfilled !== 'function' && this.state === FULFILLED ||
+    typeof onRejected !== 'function' && this.state === REJECTED) {
+    return this;
+  }
+  var promise = new this.constructor(INTERNAL);
+  if (this.state !== PENDING) {
+    var resolver = this.state === FULFILLED ? onFulfilled : onRejected;
+    unwrap(promise, resolver, this.outcome);
+  } else {
+    this.queue.push(new QueueItem(promise, onFulfilled, onRejected));
+  }
+
+  return promise;
+};
+function QueueItem(promise, onFulfilled, onRejected) {
+  this.promise = promise;
+  if (typeof onFulfilled === 'function') {
+    this.onFulfilled = onFulfilled;
+    this.callFulfilled = this.otherCallFulfilled;
+  }
+  if (typeof onRejected === 'function') {
+    this.onRejected = onRejected;
+    this.callRejected = this.otherCallRejected;
+  }
+}
+QueueItem.prototype.callFulfilled = function (value) {
+  handlers.resolve(this.promise, value);
+};
+QueueItem.prototype.otherCallFulfilled = function (value) {
+  unwrap(this.promise, this.onFulfilled, value);
+};
+QueueItem.prototype.callRejected = function (value) {
+  handlers.reject(this.promise, value);
+};
+QueueItem.prototype.otherCallRejected = function (value) {
+  unwrap(this.promise, this.onRejected, value);
+};
+
+function unwrap(promise, func, value) {
+  immediate(function () {
+    var returnValue;
+    try {
+      returnValue = func(value);
+    } catch (e) {
+      return handlers.reject(promise, e);
+    }
+    if (returnValue === promise) {
+      handlers.reject(promise, new TypeError('Cannot resolve promise with itself'));
+    } else {
+      handlers.resolve(promise, returnValue);
+    }
+  });
+}
+
+handlers.resolve = function (self, value) {
+  var result = tryCatch(getThen, value);
+  if (result.status === 'error') {
+    return handlers.reject(self, result.value);
+  }
+  var thenable = result.value;
+
+  if (thenable) {
+    safelyResolveThenable(self, thenable);
+  } else {
+    self.state = FULFILLED;
+    self.outcome = value;
+    var i = -1;
+    var len = self.queue.length;
+    while (++i < len) {
+      self.queue[i].callFulfilled(value);
+    }
+  }
+  return self;
+};
+handlers.reject = function (self, error) {
+  self.state = REJECTED;
+  self.outcome = error;
+  var i = -1;
+  var len = self.queue.length;
+  while (++i < len) {
+    self.queue[i].callRejected(error);
+  }
+  return self;
+};
+
+function getThen(obj) {
+  // Make sure we only access the accessor once as required by the spec
+  var then = obj && obj.then;
+  if (obj && (typeof obj === 'object' || typeof obj === 'function') && typeof then === 'function') {
+    return function appyThen() {
+      then.apply(obj, arguments);
+    };
+  }
+}
+
+function safelyResolveThenable(self, thenable) {
+  // Either fulfill, reject or reject with error
+  var called = false;
+  function onError(value) {
+    if (called) {
+      return;
+    }
+    called = true;
+    handlers.reject(self, value);
+  }
+
+  function onSuccess(value) {
+    if (called) {
+      return;
+    }
+    called = true;
+    handlers.resolve(self, value);
+  }
+
+  function tryToUnwrap() {
+    thenable(onSuccess, onError);
+  }
+
+  var result = tryCatch(tryToUnwrap);
+  if (result.status === 'error') {
+    onError(result.value);
+  }
+}
+
+function tryCatch(func, value) {
+  var out = {};
+  try {
+    out.value = func(value);
+    out.status = 'success';
+  } catch (e) {
+    out.status = 'error';
+    out.value = e;
+  }
+  return out;
+}
+
+Promise.resolve = resolve;
+function resolve(value) {
+  if (value instanceof this) {
+    return value;
+  }
+  return handlers.resolve(new this(INTERNAL), value);
+}
+
+Promise.reject = reject;
+function reject(reason) {
+  var promise = new this(INTERNAL);
+  return handlers.reject(promise, reason);
+}
+
+Promise.all = all;
+function all(iterable) {
+  var self = this;
+  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
+    return this.reject(new TypeError('must be an array'));
+  }
+
+  var len = iterable.length;
+  var called = false;
+  if (!len) {
+    return this.resolve([]);
+  }
+
+  var values = new Array(len);
+  var resolved = 0;
+  var i = -1;
+  var promise = new this(INTERNAL);
+
+  while (++i < len) {
+    allResolver(iterable[i], i);
+  }
+  return promise;
+  function allResolver(value, i) {
+    self.resolve(value).then(resolveFromAll, function (error) {
+      if (!called) {
+        called = true;
+        handlers.reject(promise, error);
+      }
+    });
+    function resolveFromAll(outValue) {
+      values[i] = outValue;
+      if (++resolved === len && !called) {
+        called = true;
+        handlers.resolve(promise, values);
+      }
+    }
+  }
+}
+
+Promise.race = race;
+function race(iterable) {
+  var self = this;
+  if (Object.prototype.toString.call(iterable) !== '[object Array]') {
+    return this.reject(new TypeError('must be an array'));
+  }
+
+  var len = iterable.length;
+  var called = false;
+  if (!len) {
+    return this.resolve([]);
+  }
+
+  var i = -1;
+  var promise = new this(INTERNAL);
+
+  while (++i < len) {
+    resolver(iterable[i]);
+  }
+  return promise;
+  function resolver(value) {
+    self.resolve(value).then(function (response) {
+      if (!called) {
+        called = true;
+        handlers.resolve(promise, response);
+      }
+    }, function (error) {
+      if (!called) {
+        called = true;
+        handlers.reject(promise, error);
+      }
+    });
+  }
+}
+
+},{"immediate":36}],38:[function(require,module,exports){
+// Top level file is just a mixin of submodules & constants
+'use strict';
+
+var assign    = require('./lib/utils/common').assign;
+
+var deflate   = require('./lib/deflate');
+var inflate   = require('./lib/inflate');
+var constants = require('./lib/zlib/constants');
+
+var pako = {};
+
+assign(pako, deflate, inflate, constants);
+
+module.exports = pako;
+
+},{"./lib/deflate":39,"./lib/inflate":40,"./lib/utils/common":41,"./lib/zlib/constants":44}],39:[function(require,module,exports){
+'use strict';
+
+
+var zlib_deflate = require('./zlib/deflate');
+var utils        = require('./utils/common');
+var strings      = require('./utils/strings');
+var msg          = require('./zlib/messages');
+var ZStream      = require('./zlib/zstream');
+
+var toString = Object.prototype.toString;
+
+/* Public constants ==========================================================*/
+/* ===========================================================================*/
+
+var Z_NO_FLUSH      = 0;
+var Z_FINISH        = 4;
+
+var Z_OK            = 0;
+var Z_STREAM_END    = 1;
+var Z_SYNC_FLUSH    = 2;
+
+var Z_DEFAULT_COMPRESSION = -1;
+
+var Z_DEFAULT_STRATEGY    = 0;
+
+var Z_DEFLATED  = 8;
+
+/* ===========================================================================*/
+
+
+/**
+ * class Deflate
+ *
+ * Generic JS-style wrapper for zlib calls. If you don't need
+ * streaming behaviour - use more simple functions: [[deflate]],
+ * [[deflateRaw]] and [[gzip]].
+ **/
+
+/* internal
+ * Deflate.chunks -> Array
+ *
+ * Chunks of output data, if [[Deflate#onData]] not overriden.
+ **/
+
+/**
+ * Deflate.result -> Uint8Array|Array
+ *
+ * Compressed result, generated by default [[Deflate#onData]]
+ * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
+ * (call [[Deflate#push]] with `Z_FINISH` / `true` param)  or if you
+ * push a chunk with explicit flush (call [[Deflate#push]] with
+ * `Z_SYNC_FLUSH` param).
+ **/
+
+/**
+ * Deflate.err -> Number
+ *
+ * Error code after deflate finished. 0 (Z_OK) on success.
+ * You will not need it in real life, because deflate errors
+ * are possible only on wrong options or bad `onData` / `onEnd`
+ * custom handlers.
+ **/
+
+/**
+ * Deflate.msg -> String
+ *
+ * Error message, if [[Deflate.err]] != 0
+ **/
+
+
+/**
+ * new Deflate(options)
+ * - options (Object): zlib deflate options.
+ *
+ * Creates new deflator instance with specified params. Throws exception
+ * on bad params. Supported options:
+ *
+ * - `level`
+ * - `windowBits`
+ * - `memLevel`
+ * - `strategy`
+ * - `dictionary`
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information on these.
+ *
+ * Additional options, for internal needs:
+ *
+ * - `chunkSize` - size of generated data chunks (16K by default)
+ * - `raw` (Boolean) - do raw deflate
+ * - `gzip` (Boolean) - create gzip wrapper
+ * - `to` (String) - if equal to 'string', then result will be "binary string"
+ *    (each char code [0..255])
+ * - `header` (Object) - custom header for gzip
+ *   - `text` (Boolean) - true if compressed data believed to be text
+ *   - `time` (Number) - modification time, unix timestamp
+ *   - `os` (Number) - operation system code
+ *   - `extra` (Array) - array of bytes with extra data (max 65536)
+ *   - `name` (String) - file name (binary string)
+ *   - `comment` (String) - comment (binary string)
+ *   - `hcrc` (Boolean) - true if header crc should be added
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
+ *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
+ *
+ * var deflate = new pako.Deflate({ level: 3});
+ *
+ * deflate.push(chunk1, false);
+ * deflate.push(chunk2, true);  // true -> last chunk
+ *
+ * if (deflate.err) { throw new Error(deflate.err); }
+ *
+ * console.log(deflate.result);
+ * ```
+ **/
+function Deflate(options) {
+  if (!(this instanceof Deflate)) return new Deflate(options);
+
+  this.options = utils.assign({
+    level: Z_DEFAULT_COMPRESSION,
+    method: Z_DEFLATED,
+    chunkSize: 16384,
+    windowBits: 15,
+    memLevel: 8,
+    strategy: Z_DEFAULT_STRATEGY,
+    to: ''
+  }, options || {});
+
+  var opt = this.options;
+
+  if (opt.raw && (opt.windowBits > 0)) {
+    opt.windowBits = -opt.windowBits;
+  }
+
+  else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
+    opt.windowBits += 16;
+  }
+
+  this.err    = 0;      // error code, if happens (0 = Z_OK)
+  this.msg    = '';     // error message
+  this.ended  = false;  // used to avoid multiple onEnd() calls
+  this.chunks = [];     // chunks of compressed data
+
+  this.strm = new ZStream();
+  this.strm.avail_out = 0;
+
+  var status = zlib_deflate.deflateInit2(
+    this.strm,
+    opt.level,
+    opt.method,
+    opt.windowBits,
+    opt.memLevel,
+    opt.strategy
+  );
+
+  if (status !== Z_OK) {
+    throw new Error(msg[status]);
+  }
+
+  if (opt.header) {
+    zlib_deflate.deflateSetHeader(this.strm, opt.header);
+  }
+
+  if (opt.dictionary) {
+    var dict;
+    // Convert data if needed
+    if (typeof opt.dictionary === 'string') {
+      // If we need to compress text, change encoding to utf8.
+      dict = strings.string2buf(opt.dictionary);
+    } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') {
+      dict = new Uint8Array(opt.dictionary);
+    } else {
+      dict = opt.dictionary;
+    }
+
+    status = zlib_deflate.deflateSetDictionary(this.strm, dict);
+
+    if (status !== Z_OK) {
+      throw new Error(msg[status]);
+    }
+
+    this._dict_set = true;
+  }
+}
+
+/**
+ * Deflate#push(data[, mode]) -> Boolean
+ * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
+ *   converted to utf8 byte sequence.
+ * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
+ *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
+ *
+ * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
+ * new compressed chunks. Returns `true` on success. The last data block must have
+ * mode Z_FINISH (or `true`). That will flush internal pending buffers and call
+ * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
+ * can use mode Z_SYNC_FLUSH, keeping the compression context.
+ *
+ * On fail call [[Deflate#onEnd]] with error code and return false.
+ *
+ * We strongly recommend to use `Uint8Array` on input for best speed (output
+ * array format is detected automatically). Also, don't skip last param and always
+ * use the same type in your code (boolean or number). That will improve JS speed.
+ *
+ * For regular `Array`-s make sure all elements are [0..255].
+ *
+ * ##### Example
+ *
+ * ```javascript
+ * push(chunk, false); // push one of data chunks
+ * ...
+ * push(chunk, true);  // push last chunk
+ * ```
+ **/
+Deflate.prototype.push = function (data, mode) {
+  var strm = this.strm;
+  var chunkSize = this.options.chunkSize;
+  var status, _mode;
+
+  if (this.ended) { return false; }
+
+  _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
+
+  // Convert data if needed
+  if (typeof data === 'string') {
+    // If we need to compress text, change encoding to utf8.
+    strm.input = strings.string2buf(data);
+  } else if (toString.call(data) === '[object ArrayBuffer]') {
+    strm.input = new Uint8Array(data);
+  } else {
+    strm.input = data;
+  }
+
+  strm.next_in = 0;
+  strm.avail_in = strm.input.length;
+
+  do {
+    if (strm.avail_out === 0) {
+      strm.output = new utils.Buf8(chunkSize);
+      strm.next_out = 0;
+      strm.avail_out = chunkSize;
+    }
+    status = zlib_deflate.deflate(strm, _mode);    /* no bad return value */
+
+    if (status !== Z_STREAM_END && status !== Z_OK) {
+      this.onEnd(status);
+      this.ended = true;
+      return false;
+    }
+    if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
+      if (this.options.to === 'string') {
+        this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
+      } else {
+        this.onData(utils.shrinkBuf(strm.output, strm.next_out));
+      }
+    }
+  } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
+
+  // Finalize on the last chunk.
+  if (_mode === Z_FINISH) {
+    status = zlib_deflate.deflateEnd(this.strm);
+    this.onEnd(status);
+    this.ended = true;
+    return status === Z_OK;
+  }
+
+  // callback interim results if Z_SYNC_FLUSH.
+  if (_mode === Z_SYNC_FLUSH) {
+    this.onEnd(Z_OK);
+    strm.avail_out = 0;
+    return true;
+  }
+
+  return true;
+};
+
+
+/**
+ * Deflate#onData(chunk) -> Void
+ * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
+ *   on js engine support. When string output requested, each chunk
+ *   will be string.
+ *
+ * By default, stores data blocks in `chunks[]` property and glue
+ * those in `onEnd`. Override this handler, if you need another behaviour.
+ **/
+Deflate.prototype.onData = function (chunk) {
+  this.chunks.push(chunk);
+};
+
+
+/**
+ * Deflate#onEnd(status) -> Void
+ * - status (Number): deflate status. 0 (Z_OK) on success,
+ *   other if not.
+ *
+ * Called once after you tell deflate that the input stream is
+ * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
+ * or if an error happened. By default - join collected chunks,
+ * free memory and fill `results` / `err` properties.
+ **/
+Deflate.prototype.onEnd = function (status) {
+  // On success - join
+  if (status === Z_OK) {
+    if (this.options.to === 'string') {
+      this.result = this.chunks.join('');
+    } else {
+      this.result = utils.flattenChunks(this.chunks);
+    }
+  }
+  this.chunks = [];
+  this.err = status;
+  this.msg = this.strm.msg;
+};
+
+
+/**
+ * deflate(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to compress.
+ * - options (Object): zlib deflate options.
+ *
+ * Compress `data` with deflate algorithm and `options`.
+ *
+ * Supported options are:
+ *
+ * - level
+ * - windowBits
+ * - memLevel
+ * - strategy
+ * - dictionary
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information on these.
+ *
+ * Sugar (options):
+ *
+ * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
+ *   negative windowBits implicitly.
+ * - `to` (String) - if equal to 'string', then result will be "binary string"
+ *    (each char code [0..255])
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ *   , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
+ *
+ * console.log(pako.deflate(data));
+ * ```
+ **/
+function deflate(input, options) {
+  var deflator = new Deflate(options);
+
+  deflator.push(input, true);
+
+  // That will never happens, if you don't cheat with options :)
+  if (deflator.err) { throw deflator.msg || msg[deflator.err]; }
+
+  return deflator.result;
+}
+
+
+/**
+ * deflateRaw(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to compress.
+ * - options (Object): zlib deflate options.
+ *
+ * The same as [[deflate]], but creates raw data, without wrapper
+ * (header and adler32 crc).
+ **/
+function deflateRaw(input, options) {
+  options = options || {};
+  options.raw = true;
+  return deflate(input, options);
+}
+
+
+/**
+ * gzip(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to compress.
+ * - options (Object): zlib deflate options.
+ *
+ * The same as [[deflate]], but create gzip wrapper instead of
+ * deflate one.
+ **/
+function gzip(input, options) {
+  options = options || {};
+  options.gzip = true;
+  return deflate(input, options);
+}
+
+
+exports.Deflate = Deflate;
+exports.deflate = deflate;
+exports.deflateRaw = deflateRaw;
+exports.gzip = gzip;
+
+},{"./utils/common":41,"./utils/strings":42,"./zlib/deflate":46,"./zlib/messages":51,"./zlib/zstream":53}],40:[function(require,module,exports){
+'use strict';
+
+
+var zlib_inflate = require('./zlib/inflate');
+var utils        = require('./utils/common');
+var strings      = require('./utils/strings');
+var c            = require('./zlib/constants');
+var msg          = require('./zlib/messages');
+var ZStream      = require('./zlib/zstream');
+var GZheader     = require('./zlib/gzheader');
+
+var toString = Object.prototype.toString;
+
+/**
+ * class Inflate
+ *
+ * Generic JS-style wrapper for zlib calls. If you don't need
+ * streaming behaviour - use more simple functions: [[inflate]]
+ * and [[inflateRaw]].
+ **/
+
+/* internal
+ * inflate.chunks -> Array
+ *
+ * Chunks of output data, if [[Inflate#onData]] not overriden.
+ **/
+
+/**
+ * Inflate.result -> Uint8Array|Array|String
+ *
+ * Uncompressed result, generated by default [[Inflate#onData]]
+ * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
+ * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
+ * push a chunk with explicit flush (call [[Inflate#push]] with
+ * `Z_SYNC_FLUSH` param).
+ **/
+
+/**
+ * Inflate.err -> Number
+ *
+ * Error code after inflate finished. 0 (Z_OK) on success.
+ * Should be checked if broken data possible.
+ **/
+
+/**
+ * Inflate.msg -> String
+ *
+ * Error message, if [[Inflate.err]] != 0
+ **/
+
+
+/**
+ * new Inflate(options)
+ * - options (Object): zlib inflate options.
+ *
+ * Creates new inflator instance with specified params. Throws exception
+ * on bad params. Supported options:
+ *
+ * - `windowBits`
+ * - `dictionary`
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information on these.
+ *
+ * Additional options, for internal needs:
+ *
+ * - `chunkSize` - size of generated data chunks (16K by default)
+ * - `raw` (Boolean) - do raw inflate
+ * - `to` (String) - if equal to 'string', then result will be converted
+ *   from utf8 to utf16 (javascript) string. When string output requested,
+ *   chunk length can differ from `chunkSize`, depending on content.
+ *
+ * By default, when no options set, autodetect deflate/gzip data format via
+ * wrapper header.
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ *   , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
+ *   , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
+ *
+ * var inflate = new pako.Inflate({ level: 3});
+ *
+ * inflate.push(chunk1, false);
+ * inflate.push(chunk2, true);  // true -> last chunk
+ *
+ * if (inflate.err) { throw new Error(inflate.err); }
+ *
+ * console.log(inflate.result);
+ * ```
+ **/
+function Inflate(options) {
+  if (!(this instanceof Inflate)) return new Inflate(options);
+
+  this.options = utils.assign({
+    chunkSize: 16384,
+    windowBits: 0,
+    to: ''
+  }, options || {});
+
+  var opt = this.options;
+
+  // Force window size for `raw` data, if not set directly,
+  // because we have no header for autodetect.
+  if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
+    opt.windowBits = -opt.windowBits;
+    if (opt.windowBits === 0) { opt.windowBits = -15; }
+  }
+
+  // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
+  if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
+      !(options && options.windowBits)) {
+    opt.windowBits += 32;
+  }
+
+  // Gzip header has no info about windows size, we can do autodetect only
+  // for deflate. So, if window size not set, force it to max when gzip possible
+  if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
+    // bit 3 (16) -> gzipped data
+    // bit 4 (32) -> autodetect gzip/deflate
+    if ((opt.windowBits & 15) === 0) {
+      opt.windowBits |= 15;
+    }
+  }
+
+  this.err    = 0;      // error code, if happens (0 = Z_OK)
+  this.msg    = '';     // error message
+  this.ended  = false;  // used to avoid multiple onEnd() calls
+  this.chunks = [];     // chunks of compressed data
+
+  this.strm   = new ZStream();
+  this.strm.avail_out = 0;
+
+  var status  = zlib_inflate.inflateInit2(
+    this.strm,
+    opt.windowBits
+  );
+
+  if (status !== c.Z_OK) {
+    throw new Error(msg[status]);
+  }
+
+  this.header = new GZheader();
+
+  zlib_inflate.inflateGetHeader(this.strm, this.header);
+}
+
+/**
+ * Inflate#push(data[, mode]) -> Boolean
+ * - data (Uint8Array|Array|ArrayBuffer|String): input data
+ * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
+ *   See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
+ *
+ * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
+ * new output chunks. Returns `true` on success. The last data block must have
+ * mode Z_FINISH (or `true`). That will flush internal pending buffers and call
+ * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
+ * can use mode Z_SYNC_FLUSH, keeping the decompression context.
+ *
+ * On fail call [[Inflate#onEnd]] with error code and return false.
+ *
+ * We strongly recommend to use `Uint8Array` on input for best speed (output
+ * format is detected automatically). Also, don't skip last param and always
+ * use the same type in your code (boolean or number). That will improve JS speed.
+ *
+ * For regular `Array`-s make sure all elements are [0..255].
+ *
+ * ##### Example
+ *
+ * ```javascript
+ * push(chunk, false); // push one of data chunks
+ * ...
+ * push(chunk, true);  // push last chunk
+ * ```
+ **/
+Inflate.prototype.push = function (data, mode) {
+  var strm = this.strm;
+  var chunkSize = this.options.chunkSize;
+  var dictionary = this.options.dictionary;
+  var status, _mode;
+  var next_out_utf8, tail, utf8str;
+  var dict;
+
+  // Flag to properly process Z_BUF_ERROR on testing inflate call
+  // when we check that all output data was flushed.
+  var allowBufError = false;
+
+  if (this.ended) { return false; }
+  _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
+
+  // Convert data if needed
+  if (typeof data === 'string') {
+    // Only binary strings can be decompressed on practice
+    strm.input = strings.binstring2buf(data);
+  } else if (toString.call(data) === '[object ArrayBuffer]') {
+    strm.input = new Uint8Array(data);
+  } else {
+    strm.input = data;
+  }
+
+  strm.next_in = 0;
+  strm.avail_in = strm.input.length;
+
+  do {
+    if (strm.avail_out === 0) {
+      strm.output = new utils.Buf8(chunkSize);
+      strm.next_out = 0;
+      strm.avail_out = chunkSize;
+    }
+
+    status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH);    /* no bad return value */
+
+    if (status === c.Z_NEED_DICT && dictionary) {
+      // Convert data if needed
+      if (typeof dictionary === 'string') {
+        dict = strings.string2buf(dictionary);
+      } else if (toString.call(dictionary) === '[object ArrayBuffer]') {
+        dict = new Uint8Array(dictionary);
+      } else {
+        dict = dictionary;
+      }
+
+      status = zlib_inflate.inflateSetDictionary(this.strm, dict);
+
+    }
+
+    if (status === c.Z_BUF_ERROR && allowBufError === true) {
+      status = c.Z_OK;
+      allowBufError = false;
+    }
+
+    if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
+      this.onEnd(status);
+      this.ended = true;
+      return false;
+    }
+
+    if (strm.next_out) {
+      if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) {
+
+        if (this.options.to === 'string') {
+
+          next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
+
+          tail = strm.next_out - next_out_utf8;
+          utf8str = strings.buf2string(strm.output, next_out_utf8);
+
+          // move tail
+          strm.next_out = tail;
+          strm.avail_out = chunkSize - tail;
+          if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
+
+          this.onData(utf8str);
+
+        } else {
+          this.onData(utils.shrinkBuf(strm.output, strm.next_out));
+        }
+      }
+    }
+
+    // When no more input data, we should check that internal inflate buffers
+    // are flushed. The only way to do it when avail_out = 0 - run one more
+    // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
+    // Here we set flag to process this error properly.
+    //
+    // NOTE. Deflate does not return error in this case and does not needs such
+    // logic.
+    if (strm.avail_in === 0 && strm.avail_out === 0) {
+      allowBufError = true;
+    }
+
+  } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END);
+
+  if (status === c.Z_STREAM_END) {
+    _mode = c.Z_FINISH;
+  }
+
+  // Finalize on the last chunk.
+  if (_mode === c.Z_FINISH) {
+    status = zlib_inflate.inflateEnd(this.strm);
+    this.onEnd(status);
+    this.ended = true;
+    return status === c.Z_OK;
+  }
+
+  // callback interim results if Z_SYNC_FLUSH.
+  if (_mode === c.Z_SYNC_FLUSH) {
+    this.onEnd(c.Z_OK);
+    strm.avail_out = 0;
+    return true;
+  }
+
+  return true;
+};
+
+
+/**
+ * Inflate#onData(chunk) -> Void
+ * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
+ *   on js engine support. When string output requested, each chunk
+ *   will be string.
+ *
+ * By default, stores data blocks in `chunks[]` property and glue
+ * those in `onEnd`. Override this handler, if you need another behaviour.
+ **/
+Inflate.prototype.onData = function (chunk) {
+  this.chunks.push(chunk);
+};
+
+
+/**
+ * Inflate#onEnd(status) -> Void
+ * - status (Number): inflate status. 0 (Z_OK) on success,
+ *   other if not.
+ *
+ * Called either after you tell inflate that the input stream is
+ * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
+ * or if an error happened. By default - join collected chunks,
+ * free memory and fill `results` / `err` properties.
+ **/
+Inflate.prototype.onEnd = function (status) {
+  // On success - join
+  if (status === c.Z_OK) {
+    if (this.options.to === 'string') {
+      // Glue & convert here, until we teach pako to send
+      // utf8 alligned strings to onData
+      this.result = this.chunks.join('');
+    } else {
+      this.result = utils.flattenChunks(this.chunks);
+    }
+  }
+  this.chunks = [];
+  this.err = status;
+  this.msg = this.strm.msg;
+};
+
+
+/**
+ * inflate(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * Decompress `data` with inflate/ungzip and `options`. Autodetect
+ * format via wrapper header by default. That's why we don't provide
+ * separate `ungzip` method.
+ *
+ * Supported options are:
+ *
+ * - windowBits
+ *
+ * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
+ * for more information.
+ *
+ * Sugar (options):
+ *
+ * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
+ *   negative windowBits implicitly.
+ * - `to` (String) - if equal to 'string', then result will be converted
+ *   from utf8 to utf16 (javascript) string. When string output requested,
+ *   chunk length can differ from `chunkSize`, depending on content.
+ *
+ *
+ * ##### Example:
+ *
+ * ```javascript
+ * var pako = require('pako')
+ *   , input = pako.deflate([1,2,3,4,5,6,7,8,9])
+ *   , output;
+ *
+ * try {
+ *   output = pako.inflate(input);
+ * } catch (err)
+ *   console.log(err);
+ * }
+ * ```
+ **/
+function inflate(input, options) {
+  var inflator = new Inflate(options);
+
+  inflator.push(input, true);
+
+  // That will never happens, if you don't cheat with options :)
+  if (inflator.err) { throw inflator.msg || msg[inflator.err]; }
+
+  return inflator.result;
+}
+
+
+/**
+ * inflateRaw(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * The same as [[inflate]], but creates raw data, without wrapper
+ * (header and adler32 crc).
+ **/
+function inflateRaw(input, options) {
+  options = options || {};
+  options.raw = true;
+  return inflate(input, options);
+}
+
+
+/**
+ * ungzip(data[, options]) -> Uint8Array|Array|String
+ * - data (Uint8Array|Array|String): input data to decompress.
+ * - options (Object): zlib inflate options.
+ *
+ * Just shortcut to [[inflate]], because it autodetects format
+ * by header.content. Done for convenience.
+ **/
+
+
+exports.Inflate = Inflate;
+exports.inflate = inflate;
+exports.inflateRaw = inflateRaw;
+exports.ungzip  = inflate;
+
+},{"./utils/common":41,"./utils/strings":42,"./zlib/constants":44,"./zlib/gzheader":47,"./zlib/inflate":49,"./zlib/messages":51,"./zlib/zstream":53}],41:[function(require,module,exports){
+'use strict';
+
+
+var TYPED_OK =  (typeof Uint8Array !== 'undefined') &&
+                (typeof Uint16Array !== 'undefined') &&
+                (typeof Int32Array !== 'undefined');
+
+
+exports.assign = function (obj /*from1, from2, from3, ...*/) {
+  var sources = Array.prototype.slice.call(arguments, 1);
+  while (sources.length) {
+    var source = sources.shift();
+    if (!source) { continue; }
+
+    if (typeof source !== 'object') {
+      throw new TypeError(source + 'must be non-object');
+    }
+
+    for (var p in source) {
+      if (source.hasOwnProperty(p)) {
+        obj[p] = source[p];
+      }
+    }
+  }
+
+  return obj;
+};
+
+
+// reduce buffer size, avoiding mem copy
+exports.shrinkBuf = function (buf, size) {
+  if (buf.length === size) { return buf; }
+  if (buf.subarray) { return buf.subarray(0, size); }
+  buf.length = size;
+  return buf;
+};
+
+
+var fnTyped = {
+  arraySet: function (dest, src, src_offs, len, dest_offs) {
+    if (src.subarray && dest.subarray) {
+      dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
+      return;
+    }
+    // Fallback to ordinary array
+    for (var i = 0; i < len; i++) {
+      dest[dest_offs + i] = src[src_offs + i];
+    }
+  },
+  // Join array of chunks to single array.
+  flattenChunks: function (chunks) {
+    var i, l, len, pos, chunk, result;
+
+    // calculate data length
+    len = 0;
+    for (i = 0, l = chunks.length; i < l; i++) {
+      len += chunks[i].length;
+    }
+
+    // join chunks
+    result = new Uint8Array(len);
+    pos = 0;
+    for (i = 0, l = chunks.length; i < l; i++) {
+      chunk = chunks[i];
+      result.set(chunk, pos);
+      pos += chunk.length;
+    }
+
+    return result;
+  }
+};
+
+var fnUntyped = {
+  arraySet: function (dest, src, src_offs, len, dest_offs) {
+    for (var i = 0; i < len; i++) {
+      dest[dest_offs + i] = src[src_offs + i];
+    }
+  },
+  // Join array of chunks to single array.
+  flattenChunks: function (chunks) {
+    return [].concat.apply([], chunks);
+  }
+};
+
+
+// Enable/Disable typed arrays use, for testing
+//
+exports.setTyped = function (on) {
+  if (on) {
+    exports.Buf8  = Uint8Array;
+    exports.Buf16 = Uint16Array;
+    exports.Buf32 = Int32Array;
+    exports.assign(exports, fnTyped);
+  } else {
+    exports.Buf8  = Array;
+    exports.Buf16 = Array;
+    exports.Buf32 = Array;
+    exports.assign(exports, fnUntyped);
+  }
+};
+
+exports.setTyped(TYPED_OK);
+
+},{}],42:[function(require,module,exports){
+// String encode/decode helpers
+'use strict';
+
+
+var utils = require('./common');
+
+
+// Quick check if we can use fast array to bin string conversion
+//
+// - apply(Array) can fail on Android 2.2
+// - apply(Uint8Array) can fail on iOS 5.1 Safary
+//
+var STR_APPLY_OK = true;
+var STR_APPLY_UIA_OK = true;
+
+try { String.fromCharCode.apply(null, [ 0 ]); } catch (__) { STR_APPLY_OK = false; }
+try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; }
+
+
+// Table with utf8 lengths (calculated by first byte of sequence)
+// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
+// because max possible codepoint is 0x10ffff
+var _utf8len = new utils.Buf8(256);
+for (var q = 0; q < 256; q++) {
+  _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1);
+}
+_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
+
+
+// convert string to array (typed, when possible)
+exports.string2buf = function (str) {
+  var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
+
+  // count binary size
+  for (m_pos = 0; m_pos < str_len; m_pos++) {
+    c = str.charCodeAt(m_pos);
+    if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
+      c2 = str.charCodeAt(m_pos + 1);
+      if ((c2 & 0xfc00) === 0xdc00) {
+        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+        m_pos++;
+      }
+    }
+    buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
+  }
+
+  // allocate buffer
+  buf = new utils.Buf8(buf_len);
+
+  // convert
+  for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
+    c = str.charCodeAt(m_pos);
+    if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) {
+      c2 = str.charCodeAt(m_pos + 1);
+      if ((c2 & 0xfc00) === 0xdc00) {
+        c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
+        m_pos++;
+      }
+    }
+    if (c < 0x80) {
+      /* one byte */
+      buf[i++] = c;
+    } else if (c < 0x800) {
+      /* two bytes */
+      buf[i++] = 0xC0 | (c >>> 6);
+      buf[i++] = 0x80 | (c & 0x3f);
+    } else if (c < 0x10000) {
+      /* three bytes */
+      buf[i++] = 0xE0 | (c >>> 12);
+      buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+      buf[i++] = 0x80 | (c & 0x3f);
+    } else {
+      /* four bytes */
+      buf[i++] = 0xf0 | (c >>> 18);
+      buf[i++] = 0x80 | (c >>> 12 & 0x3f);
+      buf[i++] = 0x80 | (c >>> 6 & 0x3f);
+      buf[i++] = 0x80 | (c & 0x3f);
+    }
+  }
+
+  return buf;
+};
+
+// Helper (used in 2 places)
+function buf2binstring(buf, len) {
+  // use fallback for big arrays to avoid stack overflow
+  if (len < 65537) {
+    if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
+      return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
+    }
+  }
+
+  var result = '';
+  for (var i = 0; i < len; i++) {
+    result += String.fromCharCode(buf[i]);
+  }
+  return result;
+}
+
+
+// Convert byte array to binary string
+exports.buf2binstring = function (buf) {
+  return buf2binstring(buf, buf.length);
+};
+
+
+// Convert binary string (typed, when possible)
+exports.binstring2buf = function (str) {
+  var buf = new utils.Buf8(str.length);
+  for (var i = 0, len = buf.length; i < len; i++) {
+    buf[i] = str.charCodeAt(i);
+  }
+  return buf;
+};
+
+
+// convert array to string
+exports.buf2string = function (buf, max) {
+  var i, out, c, c_len;
+  var len = max || buf.length;
+
+  // Reserve max possible length (2 words per char)
+  // NB: by unknown reasons, Array is significantly faster for
+  //     String.fromCharCode.apply than Uint16Array.
+  var utf16buf = new Array(len * 2);
+
+  for (out = 0, i = 0; i < len;) {
+    c = buf[i++];
+    // quick process ascii
+    if (c < 0x80) { utf16buf[out++] = c; continue; }
+
+    c_len = _utf8len[c];
+    // skip 5 & 6 byte codes
+    if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; }
+
+    // apply mask on first byte
+    c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
+    // join the rest
+    while (c_len > 1 && i < len) {
+      c = (c << 6) | (buf[i++] & 0x3f);
+      c_len--;
+    }
+
+    // terminated by end of string?
+    if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
+
+    if (c < 0x10000) {
+      utf16buf[out++] = c;
+    } else {
+      c -= 0x10000;
+      utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
+      utf16buf[out++] = 0xdc00 | (c & 0x3ff);
+    }
+  }
+
+  return buf2binstring(utf16buf, out);
+};
+
+
+// Calculate max possible position in utf8 buffer,
+// that will not break sequence. If that's not possible
+// - (very small limits) return max size as is.
+//
+// buf[] - utf8 bytes array
+// max   - length limit (mandatory);
+exports.utf8border = function (buf, max) {
+  var pos;
+
+  max = max || buf.length;
+  if (max > buf.length) { max = buf.length; }
+
+  // go back from last position, until start of sequence found
+  pos = max - 1;
+  while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
+
+  // Fuckup - very small and broken sequence,
+  // return max, because we should return something anyway.
+  if (pos < 0) { return max; }
+
+  // If we came to start of buffer - that means vuffer is too small,
+  // return max too.
+  if (pos === 0) { return max; }
+
+  return (pos + _utf8len[buf[pos]] > max) ? pos : max;
+};
+
+},{"./common":41}],43:[function(require,module,exports){
+'use strict';
+
+// Note: adler32 takes 12% for level 0 and 2% for level 6.
+// It doesn't worth to make additional optimizationa as in original.
+// Small size is preferable.
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+function adler32(adler, buf, len, pos) {
+  var s1 = (adler & 0xffff) |0,
+      s2 = ((adler >>> 16) & 0xffff) |0,
+      n = 0;
+
+  while (len !== 0) {
+    // Set limit ~ twice less than 5552, to keep
+    // s2 in 31-bits, because we force signed ints.
+    // in other case %= will fail.
+    n = len > 2000 ? 2000 : len;
+    len -= n;
+
+    do {
+      s1 = (s1 + buf[pos++]) |0;
+      s2 = (s2 + s1) |0;
+    } while (--n);
+
+    s1 %= 65521;
+    s2 %= 65521;
+  }
+
+  return (s1 | (s2 << 16)) |0;
+}
+
+
+module.exports = adler32;
+
+},{}],44:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+module.exports = {
+
+  /* Allowed flush values; see deflate() and inflate() below for details */
+  Z_NO_FLUSH:         0,
+  Z_PARTIAL_FLUSH:    1,
+  Z_SYNC_FLUSH:       2,
+  Z_FULL_FLUSH:       3,
+  Z_FINISH:           4,
+  Z_BLOCK:            5,
+  Z_TREES:            6,
+
+  /* Return codes for the compression/decompression functions. Negative values
+  * are errors, positive values are used for special but normal events.
+  */
+  Z_OK:               0,
+  Z_STREAM_END:       1,
+  Z_NEED_DICT:        2,
+  Z_ERRNO:           -1,
+  Z_STREAM_ERROR:    -2,
+  Z_DATA_ERROR:      -3,
+  //Z_MEM_ERROR:     -4,
+  Z_BUF_ERROR:       -5,
+  //Z_VERSION_ERROR: -6,
+
+  /* compression levels */
+  Z_NO_COMPRESSION:         0,
+  Z_BEST_SPEED:             1,
+  Z_BEST_COMPRESSION:       9,
+  Z_DEFAULT_COMPRESSION:   -1,
+
+
+  Z_FILTERED:               1,
+  Z_HUFFMAN_ONLY:           2,
+  Z_RLE:                    3,
+  Z_FIXED:                  4,
+  Z_DEFAULT_STRATEGY:       0,
+
+  /* Possible values of the data_type field (though see inflate()) */
+  Z_BINARY:                 0,
+  Z_TEXT:                   1,
+  //Z_ASCII:                1, // = Z_TEXT (deprecated)
+  Z_UNKNOWN:                2,
+
+  /* The deflate compression method */
+  Z_DEFLATED:               8
+  //Z_NULL:                 null // Use -1 or null inline, depending on var type
+};
+
+},{}],45:[function(require,module,exports){
+'use strict';
+
+// Note: we can't get significant speed boost here.
+// So write code to minimize size - no pregenerated tables
+// and array tools dependencies.
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+// Use ordinary array, since untyped makes no boost here
+function makeTable() {
+  var c, table = [];
+
+  for (var n = 0; n < 256; n++) {
+    c = n;
+    for (var k = 0; k < 8; k++) {
+      c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
+    }
+    table[n] = c;
+  }
+
+  return table;
+}
+
+// Create table on load. Just 255 signed longs. Not a problem.
+var crcTable = makeTable();
+
+
+function crc32(crc, buf, len, pos) {
+  var t = crcTable,
+      end = pos + len;
+
+  crc ^= -1;
+
+  for (var i = pos; i < end; i++) {
+    crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
+  }
+
+  return (crc ^ (-1)); // >>> 0;
+}
+
+
+module.exports = crc32;
+
+},{}],46:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+var utils   = require('../utils/common');
+var trees   = require('./trees');
+var adler32 = require('./adler32');
+var crc32   = require('./crc32');
+var msg     = require('./messages');
+
+/* Public constants ==========================================================*/
+/* ===========================================================================*/
+
+
+/* Allowed flush values; see deflate() and inflate() below for details */
+var Z_NO_FLUSH      = 0;
+var Z_PARTIAL_FLUSH = 1;
+//var Z_SYNC_FLUSH    = 2;
+var Z_FULL_FLUSH    = 3;
+var Z_FINISH        = 4;
+var Z_BLOCK         = 5;
+//var Z_TREES         = 6;
+
+
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+var Z_OK            = 0;
+var Z_STREAM_END    = 1;
+//var Z_NEED_DICT     = 2;
+//var Z_ERRNO         = -1;
+var Z_STREAM_ERROR  = -2;
+var Z_DATA_ERROR    = -3;
+//var Z_MEM_ERROR     = -4;
+var Z_BUF_ERROR     = -5;
+//var Z_VERSION_ERROR = -6;
+
+
+/* compression levels */
+//var Z_NO_COMPRESSION      = 0;
+//var Z_BEST_SPEED          = 1;
+//var Z_BEST_COMPRESSION    = 9;
+var Z_DEFAULT_COMPRESSION = -1;
+
+
+var Z_FILTERED            = 1;
+var Z_HUFFMAN_ONLY        = 2;
+var Z_RLE                 = 3;
+var Z_FIXED               = 4;
+var Z_DEFAULT_STRATEGY    = 0;
+
+/* Possible values of the data_type field (though see inflate()) */
+//var Z_BINARY              = 0;
+//var Z_TEXT                = 1;
+//var Z_ASCII               = 1; // = Z_TEXT
+var Z_UNKNOWN             = 2;
+
+
+/* The deflate compression method */
+var Z_DEFLATED  = 8;
+
+/*============================================================================*/
+
+
+var MAX_MEM_LEVEL = 9;
+/* Maximum value for memLevel in deflateInit2 */
+var MAX_WBITS = 15;
+/* 32K LZ77 window */
+var DEF_MEM_LEVEL = 8;
+
+
+var LENGTH_CODES  = 29;
+/* number of length codes, not counting the special END_BLOCK code */
+var LITERALS      = 256;
+/* number of literal bytes 0..255 */
+var L_CODES       = LITERALS + 1 + LENGTH_CODES;
+/* number of Literal or Length codes, including the END_BLOCK code */
+var D_CODES       = 30;
+/* number of distance codes */
+var BL_CODES      = 19;
+/* number of codes used to transfer the bit lengths */
+var HEAP_SIZE     = 2 * L_CODES + 1;
+/* maximum heap size */
+var MAX_BITS  = 15;
+/* All codes must not exceed MAX_BITS bits */
+
+var MIN_MATCH = 3;
+var MAX_MATCH = 258;
+var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
+
+var PRESET_DICT = 0x20;
+
+var INIT_STATE = 42;
+var EXTRA_STATE = 69;
+var NAME_STATE = 73;
+var COMMENT_STATE = 91;
+var HCRC_STATE = 103;
+var BUSY_STATE = 113;
+var FINISH_STATE = 666;
+
+var BS_NEED_MORE      = 1; /* block not completed, need more input or more output */
+var BS_BLOCK_DONE     = 2; /* block flush performed */
+var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
+var BS_FINISH_DONE    = 4; /* finish done, accept no more input or output */
+
+var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
+
+function err(strm, errorCode) {
+  strm.msg = msg[errorCode];
+  return errorCode;
+}
+
+function rank(f) {
+  return ((f) << 1) - ((f) > 4 ? 9 : 0);
+}
+
+function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
+
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->output buffer and copying into it.
+ * (See also read_buf()).
+ */
+function flush_pending(strm) {
+  var s = strm.state;
+
+  //_tr_flush_bits(s);
+  var len = s.pending;
+  if (len > strm.avail_out) {
+    len = strm.avail_out;
+  }
+  if (len === 0) { return; }
+
+  utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
+  strm.next_out += len;
+  s.pending_out += len;
+  strm.total_out += len;
+  strm.avail_out -= len;
+  s.pending -= len;
+  if (s.pending === 0) {
+    s.pending_out = 0;
+  }
+}
+
+
+function flush_block_only(s, last) {
+  trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
+  s.block_start = s.strstart;
+  flush_pending(s.strm);
+}
+
+
+function put_byte(s, b) {
+  s.pending_buf[s.pending++] = b;
+}
+
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+function putShortMSB(s, b) {
+//  put_byte(s, (Byte)(b >> 8));
+//  put_byte(s, (Byte)(b & 0xff));
+  s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
+  s.pending_buf[s.pending++] = b & 0xff;
+}
+
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->input buffer and copying from it.
+ * (See also flush_pending()).
+ */
+function read_buf(strm, buf, start, size) {
+  var len = strm.avail_in;
+
+  if (len > size) { len = size; }
+  if (len === 0) { return 0; }
+
+  strm.avail_in -= len;
+
+  // zmemcpy(buf, strm->next_in, len);
+  utils.arraySet(buf, strm.input, strm.next_in, len, start);
+  if (strm.state.wrap === 1) {
+    strm.adler = adler32(strm.adler, buf, len, start);
+  }
+
+  else if (strm.state.wrap === 2) {
+    strm.adler = crc32(strm.adler, buf, len, start);
+  }
+
+  strm.next_in += len;
+  strm.total_in += len;
+
+  return len;
+}
+
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+function longest_match(s, cur_match) {
+  var chain_length = s.max_chain_length;      /* max hash chain length */
+  var scan = s.strstart; /* current string */
+  var match;                       /* matched string */
+  var len;                           /* length of current match */
+  var best_len = s.prev_length;              /* best match length so far */
+  var nice_match = s.nice_match;             /* stop if match long enough */
+  var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
+      s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
+
+  var _win = s.window; // shortcut
+
+  var wmask = s.w_mask;
+  var prev  = s.prev;
+
+  /* Stop when cur_match becomes <= limit. To simplify the code,
+   * we prevent matches with the string of window index 0.
+   */
+
+  var strend = s.strstart + MAX_MATCH;
+  var scan_end1  = _win[scan + best_len - 1];
+  var scan_end   = _win[scan + best_len];
+
+  /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+   * It is easy to get rid of this optimization if necessary.
+   */
+  // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+  /* Do not waste too much time if we already have a good match: */
+  if (s.prev_length >= s.good_match) {
+    chain_length >>= 2;
+  }
+  /* Do not look for matches beyond the end of the input. This is necessary
+   * to make deflate deterministic.
+   */
+  if (nice_match > s.lookahead) { nice_match = s.lookahead; }
+
+  // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+  do {
+    // Assert(cur_match < s->strstart, "no future");
+    match = cur_match;
+
+    /* Skip to next match if the match length cannot increase
+     * or if the match length is less than 2.  Note that the checks below
+     * for insufficient lookahead only occur occasionally for performance
+     * reasons.  Therefore uninitialized memory will be accessed, and
+     * conditional jumps will be made that depend on those values.
+     * However the length of the match is limited to the lookahead, so
+     * the output of deflate is not affected by the uninitialized values.
+     */
+
+    if (_win[match + best_len]     !== scan_end  ||
+        _win[match + best_len - 1] !== scan_end1 ||
+        _win[match]                !== _win[scan] ||
+        _win[++match]              !== _win[scan + 1]) {
+      continue;
+    }
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2;
+    match++;
+    // Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+      /*jshint noempty:false*/
+    } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
+             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
+             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
+             _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
+             scan < strend);
+
+    // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (strend - scan);
+    scan = strend - MAX_MATCH;
+
+    if (len > best_len) {
+      s.match_start = cur_match;
+      best_len = len;
+      if (len >= nice_match) {
+        break;
+      }
+      scan_end1  = _win[scan + best_len - 1];
+      scan_end   = _win[scan + best_len];
+    }
+  } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
+
+  if (best_len <= s.lookahead) {
+    return best_len;
+  }
+  return s.lookahead;
+}
+
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+function fill_window(s) {
+  var _w_size = s.w_size;
+  var p, n, m, more, str;
+
+  //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+  do {
+    more = s.window_size - s.lookahead - s.strstart;
+
+    // JS ints have 32 bit, block below not needed
+    /* Deal with !@#$% 64K limit: */
+    //if (sizeof(int) <= 2) {
+    //    if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+    //        more = wsize;
+    //
+    //  } else if (more == (unsigned)(-1)) {
+    //        /* Very unlikely, but possible on 16 bit machine if
+    //         * strstart == 0 && lookahead == 1 (input done a byte at time)
+    //         */
+    //        more--;
+    //    }
+    //}
+
+
+    /* If the window is almost full and there is insufficient lookahead,
+     * move the upper half to the lower one to make room in the upper half.
+     */
+    if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
+
+      utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
+      s.match_start -= _w_size;
+      s.strstart -= _w_size;
+      /* we now have strstart >= MAX_DIST */
+      s.block_start -= _w_size;
+
+      /* Slide the hash table (could be avoided with 32 bit values
+       at the expense of memory usage). We slide even when level == 0
+       to keep the hash table consistent if we switch back to level > 0
+       later. (Using level 0 permanently is not an optimal usage of
+       zlib, so we don't care about this pathological case.)
+       */
+
+      n = s.hash_size;
+      p = n;
+      do {
+        m = s.head[--p];
+        s.head[p] = (m >= _w_size ? m - _w_size : 0);
+      } while (--n);
+
+      n = _w_size;
+      p = n;
+      do {
+        m = s.prev[--p];
+        s.prev[p] = (m >= _w_size ? m - _w_size : 0);
+        /* If n is not on any hash chain, prev[n] is garbage but
+         * its value will never be used.
+         */
+      } while (--n);
+
+      more += _w_size;
+    }
+    if (s.strm.avail_in === 0) {
+      break;
+    }
+
+    /* If there was no sliding:
+     *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+     *    more == window_size - lookahead - strstart
+     * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+     * => more >= window_size - 2*WSIZE + 2
+     * In the BIG_MEM or MMAP case (not yet supported),
+     *   window_size == input_size + MIN_LOOKAHEAD  &&
+     *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+     * Otherwise, window_size == 2*WSIZE so more >= 2.
+     * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+     */
+    //Assert(more >= 2, "more < 2");
+    n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
+    s.lookahead += n;
+
+    /* Initialize the hash value now that we have some input: */
+    if (s.lookahead + s.insert >= MIN_MATCH) {
+      str = s.strstart - s.insert;
+      s.ins_h = s.window[str];
+
+      /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
+      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
+//#if MIN_MATCH != 3
+//        Call update_hash() MIN_MATCH-3 more times
+//#endif
+      while (s.insert) {
+        /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
+        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
+
+        s.prev[str & s.w_mask] = s.head[s.ins_h];
+        s.head[s.ins_h] = str;
+        str++;
+        s.insert--;
+        if (s.lookahead + s.insert < MIN_MATCH) {
+          break;
+        }
+      }
+    }
+    /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+     * but this is not important since only literal bytes will be emitted.
+     */
+
+  } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
+
+  /* If the WIN_INIT bytes after the end of the current data have never been
+   * written, then zero those bytes in order to avoid memory check reports of
+   * the use of uninitialized (or uninitialised as Julian writes) bytes by
+   * the longest match routines.  Update the high water mark for the next
+   * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
+   * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+   */
+//  if (s.high_water < s.window_size) {
+//    var curr = s.strstart + s.lookahead;
+//    var init = 0;
+//
+//    if (s.high_water < curr) {
+//      /* Previous high water mark below current data -- zero WIN_INIT
+//       * bytes or up to end of window, whichever is less.
+//       */
+//      init = s.window_size - curr;
+//      if (init > WIN_INIT)
+//        init = WIN_INIT;
+//      zmemzero(s->window + curr, (unsigned)init);
+//      s->high_water = curr + init;
+//    }
+//    else if (s->high_water < (ulg)curr + WIN_INIT) {
+//      /* High water mark at or above current data, but below current data
+//       * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+//       * to end of window, whichever is less.
+//       */
+//      init = (ulg)curr + WIN_INIT - s->high_water;
+//      if (init > s->window_size - s->high_water)
+//        init = s->window_size - s->high_water;
+//      zmemzero(s->window + s->high_water, (unsigned)init);
+//      s->high_water += init;
+//    }
+//  }
+//
+//  Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+//    "not enough room for search");
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+function deflate_stored(s, flush) {
+  /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+   * to pending_buf_size, and each stored block has a 5 byte header:
+   */
+  var max_block_size = 0xffff;
+
+  if (max_block_size > s.pending_buf_size - 5) {
+    max_block_size = s.pending_buf_size - 5;
+  }
+
+  /* Copy as much as possible from input to output: */
+  for (;;) {
+    /* Fill the window as much as possible: */
+    if (s.lookahead <= 1) {
+
+      //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+      //  s->block_start >= (long)s->w_size, "slide too late");
+//      if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
+//        s.block_start >= s.w_size)) {
+//        throw  new Error("slide too late");
+//      }
+
+      fill_window(s);
+      if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
+        return BS_NEED_MORE;
+      }
+
+      if (s.lookahead === 0) {
+        break;
+      }
+      /* flush the current block */
+    }
+    //Assert(s->block_start >= 0L, "block gone");
+//    if (s.block_start < 0) throw new Error("block gone");
+
+    s.strstart += s.lookahead;
+    s.lookahead = 0;
+
+    /* Emit a stored block if pending_buf will be full: */
+    var max_start = s.block_start + max_block_size;
+
+    if (s.strstart === 0 || s.strstart >= max_start) {
+      /* strstart == 0 is possible when wraparound on 16-bit machine */
+      s.lookahead = s.strstart - max_start;
+      s.strstart = max_start;
+      /*** FLUSH_BLOCK(s, 0); ***/
+      flush_block_only(s, false);
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+      /***/
+
+
+    }
+    /* Flush if we may have to slide, otherwise block_start may become
+     * negative and the data will be gone:
+     */
+    if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
+      /*** FLUSH_BLOCK(s, 0); ***/
+      flush_block_only(s, false);
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+      /***/
+    }
+  }
+
+  s.insert = 0;
+
+  if (flush === Z_FINISH) {
+    /*** FLUSH_BLOCK(s, 1); ***/
+    flush_block_only(s, true);
+    if (s.strm.avail_out === 0) {
+      return BS_FINISH_STARTED;
+    }
+    /***/
+    return BS_FINISH_DONE;
+  }
+
+  if (s.strstart > s.block_start) {
+    /*** FLUSH_BLOCK(s, 0); ***/
+    flush_block_only(s, false);
+    if (s.strm.avail_out === 0) {
+      return BS_NEED_MORE;
+    }
+    /***/
+  }
+
+  return BS_NEED_MORE;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+function deflate_fast(s, flush) {
+  var hash_head;        /* head of the hash chain */
+  var bflush;           /* set if current block must be flushed */
+
+  for (;;) {
+    /* Make sure that we always have enough lookahead, except
+     * at the end of the input file. We need MAX_MATCH bytes
+     * for the next match, plus MIN_MATCH bytes to insert the
+     * string following the next match.
+     */
+    if (s.lookahead < MIN_LOOKAHEAD) {
+      fill_window(s);
+      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
+        return BS_NEED_MORE;
+      }
+      if (s.lookahead === 0) {
+        break; /* flush the current block */
+      }
+    }
+
+    /* Insert the string window[strstart .. strstart+2] in the
+     * dictionary, and set hash_head to the head of the hash chain:
+     */
+    hash_head = 0/*NIL*/;
+    if (s.lookahead >= MIN_MATCH) {
+      /*** INSERT_STRING(s, s.strstart, hash_head); ***/
+      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
+      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
+      s.head[s.ins_h] = s.strstart;
+      /***/
+    }
+
+    /* Find the longest match, discarding those <= prev_length.
+     * At this point we have always match_length < MIN_MATCH
+     */
+    if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
+      /* To simplify the code, we prevent matches with the string
+       * of window index 0 (in particular we have to avoid a match
+       * of the string with itself at the start of the input file).
+       */
+      s.match_length = longest_match(s, hash_head);
+      /* longest_match() sets match_start */
+    }
+    if (s.match_length >= MIN_MATCH) {
+      // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
+
+      /*** _tr_tally_dist(s, s.strstart - s.match_start,
+                     s.match_length - MIN_MATCH, bflush); ***/
+      bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
+
+      s.lookahead -= s.match_length;
+
+      /* Insert new strings in the hash table only if the match length
+       * is not too large. This saves time but degrades compression.
+       */
+      if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
+        s.match_length--; /* string at strstart already in table */
+        do {
+          s.strstart++;
+          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
+          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
+          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
+          s.head[s.ins_h] = s.strstart;
+          /***/
+          /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+           * always MIN_MATCH bytes ahead.
+           */
+        } while (--s.match_length !== 0);
+        s.strstart++;
+      } else
+      {
+        s.strstart += s.match_length;
+        s.match_length = 0;
+        s.ins_h = s.window[s.strstart];
+        /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
+        s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
+
+//#if MIN_MATCH != 3
+//                Call UPDATE_HASH() MIN_MATCH-3 more times
+//#endif
+        /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+         * matter since it will be recomputed at next deflate call.
+         */
+      }
+    } else {
+      /* No match, output a literal byte */
+      //Tracevv((stderr,"%c", s.window[s.strstart]));
+      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
+      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
+
+      s.lookahead--;
+      s.strstart++;
+    }
+    if (bflush) {
+      /*** FLUSH_BLOCK(s, 0); ***/
+      flush_block_only(s, false);
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+      /***/
+    }
+  }
+  s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1);
+  if (flush === Z_FINISH) {
+    /*** FLUSH_BLOCK(s, 1); ***/
+    flush_block_only(s, true);
+    if (s.strm.avail_out === 0) {
+      return BS_FINISH_STARTED;
+    }
+    /***/
+    return BS_FINISH_DONE;
+  }
+  if (s.last_lit) {
+    /*** FLUSH_BLOCK(s, 0); ***/
+    flush_block_only(s, false);
+    if (s.strm.avail_out === 0) {
+      return BS_NEED_MORE;
+    }
+    /***/
+  }
+  return BS_BLOCK_DONE;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+function deflate_slow(s, flush) {
+  var hash_head;          /* head of hash chain */
+  var bflush;              /* set if current block must be flushed */
+
+  var max_insert;
+
+  /* Process the input block. */
+  for (;;) {
+    /* Make sure that we always have enough lookahead, except
+     * at the end of the input file. We need MAX_MATCH bytes
+     * for the next match, plus MIN_MATCH bytes to insert the
+     * string following the next match.
+     */
+    if (s.lookahead < MIN_LOOKAHEAD) {
+      fill_window(s);
+      if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
+        return BS_NEED_MORE;
+      }
+      if (s.lookahead === 0) { break; } /* flush the current block */
+    }
+
+    /* Insert the string window[strstart .. strstart+2] in the
+     * dictionary, and set hash_head to the head of the hash chain:
+     */
+    hash_head = 0/*NIL*/;
+    if (s.lookahead >= MIN_MATCH) {
+      /*** INSERT_STRING(s, s.strstart, hash_head); ***/
+      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
+      hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
+      s.head[s.ins_h] = s.strstart;
+      /***/
+    }
+
+    /* Find the longest match, discarding those <= prev_length.
+     */
+    s.prev_length = s.match_length;
+    s.prev_match = s.match_start;
+    s.match_length = MIN_MATCH - 1;
+
+    if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
+        s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
+      /* To simplify the code, we prevent matches with the string
+       * of window index 0 (in particular we have to avoid a match
+       * of the string with itself at the start of the input file).
+       */
+      s.match_length = longest_match(s, hash_head);
+      /* longest_match() sets match_start */
+
+      if (s.match_length <= 5 &&
+         (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
+
+        /* If prev_match is also MIN_MATCH, match_start is garbage
+         * but we will ignore the current match anyway.
+         */
+        s.match_length = MIN_MATCH - 1;
+      }
+    }
+    /* If there was a match at the previous step and the current
+     * match is not better, output the previous match:
+     */
+    if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
+      max_insert = s.strstart + s.lookahead - MIN_MATCH;
+      /* Do not insert strings in hash table beyond this. */
+
+      //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
+
+      /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
+                     s.prev_length - MIN_MATCH, bflush);***/
+      bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH);
+      /* Insert in hash table all strings up to the end of the match.
+       * strstart-1 and strstart are already inserted. If there is not
+       * enough lookahead, the last two strings are not inserted in
+       * the hash table.
+       */
+      s.lookahead -= s.prev_length - 1;
+      s.prev_length -= 2;
+      do {
+        if (++s.strstart <= max_insert) {
+          /*** INSERT_STRING(s, s.strstart, hash_head); ***/
+          s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
+          hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
+          s.head[s.ins_h] = s.strstart;
+          /***/
+        }
+      } while (--s.prev_length !== 0);
+      s.match_available = 0;
+      s.match_length = MIN_MATCH - 1;
+      s.strstart++;
+
+      if (bflush) {
+        /*** FLUSH_BLOCK(s, 0); ***/
+        flush_block_only(s, false);
+        if (s.strm.avail_out === 0) {
+          return BS_NEED_MORE;
+        }
+        /***/
+      }
+
+    } else if (s.match_available) {
+      /* If there was no match at the previous position, output a
+       * single literal. If there was a match but the current match
+       * is longer, truncate the previous match to a single literal.
+       */
+      //Tracevv((stderr,"%c", s->window[s->strstart-1]));
+      /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
+      bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
+
+      if (bflush) {
+        /*** FLUSH_BLOCK_ONLY(s, 0) ***/
+        flush_block_only(s, false);
+        /***/
+      }
+      s.strstart++;
+      s.lookahead--;
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+    } else {
+      /* There is no previous match to compare with, wait for
+       * the next step to decide.
+       */
+      s.match_available = 1;
+      s.strstart++;
+      s.lookahead--;
+    }
+  }
+  //Assert (flush != Z_NO_FLUSH, "no flush?");
+  if (s.match_available) {
+    //Tracevv((stderr,"%c", s->window[s->strstart-1]));
+    /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
+    bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]);
+
+    s.match_available = 0;
+  }
+  s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1;
+  if (flush === Z_FINISH) {
+    /*** FLUSH_BLOCK(s, 1); ***/
+    flush_block_only(s, true);
+    if (s.strm.avail_out === 0) {
+      return BS_FINISH_STARTED;
+    }
+    /***/
+    return BS_FINISH_DONE;
+  }
+  if (s.last_lit) {
+    /*** FLUSH_BLOCK(s, 0); ***/
+    flush_block_only(s, false);
+    if (s.strm.avail_out === 0) {
+      return BS_NEED_MORE;
+    }
+    /***/
+  }
+
+  return BS_BLOCK_DONE;
+}
+
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+function deflate_rle(s, flush) {
+  var bflush;            /* set if current block must be flushed */
+  var prev;              /* byte at distance one to match */
+  var scan, strend;      /* scan goes up to strend for length of run */
+
+  var _win = s.window;
+
+  for (;;) {
+    /* Make sure that we always have enough lookahead, except
+     * at the end of the input file. We need MAX_MATCH bytes
+     * for the longest run, plus one for the unrolled loop.
+     */
+    if (s.lookahead <= MAX_MATCH) {
+      fill_window(s);
+      if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
+        return BS_NEED_MORE;
+      }
+      if (s.lookahead === 0) { break; } /* flush the current block */
+    }
+
+    /* See how many times the previous byte repeats */
+    s.match_length = 0;
+    if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
+      scan = s.strstart - 1;
+      prev = _win[scan];
+      if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
+        strend = s.strstart + MAX_MATCH;
+        do {
+          /*jshint noempty:false*/
+        } while (prev === _win[++scan] && prev === _win[++scan] &&
+                 prev === _win[++scan] && prev === _win[++scan] &&
+                 prev === _win[++scan] && prev === _win[++scan] &&
+                 prev === _win[++scan] && prev === _win[++scan] &&
+                 scan < strend);
+        s.match_length = MAX_MATCH - (strend - scan);
+        if (s.match_length > s.lookahead) {
+          s.match_length = s.lookahead;
+        }
+      }
+      //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+    }
+
+    /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+    if (s.match_length >= MIN_MATCH) {
+      //check_match(s, s.strstart, s.strstart - 1, s.match_length);
+
+      /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
+      bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
+
+      s.lookahead -= s.match_length;
+      s.strstart += s.match_length;
+      s.match_length = 0;
+    } else {
+      /* No match, output a literal byte */
+      //Tracevv((stderr,"%c", s->window[s->strstart]));
+      /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
+      bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
+
+      s.lookahead--;
+      s.strstart++;
+    }
+    if (bflush) {
+      /*** FLUSH_BLOCK(s, 0); ***/
+      flush_block_only(s, false);
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+      /***/
+    }
+  }
+  s.insert = 0;
+  if (flush === Z_FINISH) {
+    /*** FLUSH_BLOCK(s, 1); ***/
+    flush_block_only(s, true);
+    if (s.strm.avail_out === 0) {
+      return BS_FINISH_STARTED;
+    }
+    /***/
+    return BS_FINISH_DONE;
+  }
+  if (s.last_lit) {
+    /*** FLUSH_BLOCK(s, 0); ***/
+    flush_block_only(s, false);
+    if (s.strm.avail_out === 0) {
+      return BS_NEED_MORE;
+    }
+    /***/
+  }
+  return BS_BLOCK_DONE;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+function deflate_huff(s, flush) {
+  var bflush;             /* set if current block must be flushed */
+
+  for (;;) {
+    /* Make sure that we have a literal to write. */
+    if (s.lookahead === 0) {
+      fill_window(s);
+      if (s.lookahead === 0) {
+        if (flush === Z_NO_FLUSH) {
+          return BS_NEED_MORE;
+        }
+        break;      /* flush the current block */
+      }
+    }
+
+    /* Output a literal byte */
+    s.match_length = 0;
+    //Tracevv((stderr,"%c", s->window[s->strstart]));
+    /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
+    bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
+    s.lookahead--;
+    s.strstart++;
+    if (bflush) {
+      /*** FLUSH_BLOCK(s, 0); ***/
+      flush_block_only(s, false);
+      if (s.strm.avail_out === 0) {
+        return BS_NEED_MORE;
+      }
+      /***/
+    }
+  }
+  s.insert = 0;
+  if (flush === Z_FINISH) {
+    /*** FLUSH_BLOCK(s, 1); ***/
+    flush_block_only(s, true);
+    if (s.strm.avail_out === 0) {
+      return BS_FINISH_STARTED;
+    }
+    /***/
+    return BS_FINISH_DONE;
+  }
+  if (s.last_lit) {
+    /*** FLUSH_BLOCK(s, 0); ***/
+    flush_block_only(s, false);
+    if (s.strm.avail_out === 0) {
+      return BS_NEED_MORE;
+    }
+    /***/
+  }
+  return BS_BLOCK_DONE;
+}
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+function Config(good_length, max_lazy, nice_length, max_chain, func) {
+  this.good_length = good_length;
+  this.max_lazy = max_lazy;
+  this.nice_length = nice_length;
+  this.max_chain = max_chain;
+  this.func = func;
+}
+
+var configuration_table;
+
+configuration_table = [
+  /*      good lazy nice chain */
+  new Config(0, 0, 0, 0, deflate_stored),          /* 0 store only */
+  new Config(4, 4, 8, 4, deflate_fast),            /* 1 max speed, no lazy matches */
+  new Config(4, 5, 16, 8, deflate_fast),           /* 2 */
+  new Config(4, 6, 32, 32, deflate_fast),          /* 3 */
+
+  new Config(4, 4, 16, 16, deflate_slow),          /* 4 lazy matches */
+  new Config(8, 16, 32, 32, deflate_slow),         /* 5 */
+  new Config(8, 16, 128, 128, deflate_slow),       /* 6 */
+  new Config(8, 32, 128, 256, deflate_slow),       /* 7 */
+  new Config(32, 128, 258, 1024, deflate_slow),    /* 8 */
+  new Config(32, 258, 258, 4096, deflate_slow)     /* 9 max compression */
+];
+
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+function lm_init(s) {
+  s.window_size = 2 * s.w_size;
+
+  /*** CLEAR_HASH(s); ***/
+  zero(s.head); // Fill with NIL (= 0);
+
+  /* Set the default configuration parameters:
+   */
+  s.max_lazy_match = configuration_table[s.level].max_lazy;
+  s.good_match = configuration_table[s.level].good_length;
+  s.nice_match = configuration_table[s.level].nice_length;
+  s.max_chain_length = configuration_table[s.level].max_chain;
+
+  s.strstart = 0;
+  s.block_start = 0;
+  s.lookahead = 0;
+  s.insert = 0;
+  s.match_length = s.prev_length = MIN_MATCH - 1;
+  s.match_available = 0;
+  s.ins_h = 0;
+}
+
+
+function DeflateState() {
+  this.strm = null;            /* pointer back to this zlib stream */
+  this.status = 0;            /* as the name implies */
+  this.pending_buf = null;      /* output still pending */
+  this.pending_buf_size = 0;  /* size of pending_buf */
+  this.pending_out = 0;       /* next pending byte to output to the stream */
+  this.pending = 0;           /* nb of bytes in the pending buffer */
+  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
+  this.gzhead = null;         /* gzip header information to write */
+  this.gzindex = 0;           /* where in extra, name, or comment */
+  this.method = Z_DEFLATED; /* can only be DEFLATED */
+  this.last_flush = -1;   /* value of flush param for previous deflate call */
+
+  this.w_size = 0;  /* LZ77 window size (32K by default) */
+  this.w_bits = 0;  /* log2(w_size)  (8..16) */
+  this.w_mask = 0;  /* w_size - 1 */
+
+  this.window = null;
+  /* Sliding window. Input bytes are read into the second half of the window,
+   * and move to the first half later to keep a dictionary of at least wSize
+   * bytes. With this organization, matches are limited to a distance of
+   * wSize-MAX_MATCH bytes, but this ensures that IO is always
+   * performed with a length multiple of the block size.
+   */
+
+  this.window_size = 0;
+  /* Actual size of window: 2*wSize, except when the user input buffer
+   * is directly used as sliding window.
+   */
+
+  this.prev = null;
+  /* Link to older string with same hash index. To limit the size of this
+   * array to 64K, this link is maintained only for the last 32K strings.
+   * An index in this array is thus a window index modulo 32K.
+   */
+
+  this.head = null;   /* Heads of the hash chains or NIL. */
+
+  this.ins_h = 0;       /* hash index of string to be inserted */
+  this.hash_size = 0;   /* number of elements in hash table */
+  this.hash_bits = 0;   /* log2(hash_size) */
+  this.hash_mask = 0;   /* hash_size-1 */
+
+  this.hash_shift = 0;
+  /* Number of bits by which ins_h must be shifted at each input
+   * step. It must be such that after MIN_MATCH steps, the oldest
+   * byte no longer takes part in the hash key, that is:
+   *   hash_shift * MIN_MATCH >= hash_bits
+   */
+
+  this.block_start = 0;
+  /* Window position at the beginning of the current output block. Gets
+   * negative when the window is moved backwards.
+   */
+
+  this.match_length = 0;      /* length of best match */
+  this.prev_match = 0;        /* previous match */
+  this.match_available = 0;   /* set if previous match exists */
+  this.strstart = 0;          /* start of string to insert */
+  this.match_start = 0;       /* start of matching string */
+  this.lookahead = 0;         /* number of valid bytes ahead in window */
+
+  this.prev_length = 0;
+  /* Length of the best match at previous step. Matches not greater than this
+   * are discarded. This is used in the lazy match evaluation.
+   */
+
+  this.max_chain_length = 0;
+  /* To speed up deflation, hash chains are never searched beyond this
+   * length.  A higher limit improves compression ratio but degrades the
+   * speed.
+   */
+
+  this.max_lazy_match = 0;
+  /* Attempt to find a better match only when the current match is strictly
+   * smaller than this value. This mechanism is used only for compression
+   * levels >= 4.
+   */
+  // That's alias to max_lazy_match, don't use directly
+  //this.max_insert_length = 0;
+  /* Insert new strings in the hash table only if the match length is not
+   * greater than this length. This saves time but degrades compression.
+   * max_insert_length is used only for compression levels <= 3.
+   */
+
+  this.level = 0;     /* compression level (1..9) */
+  this.strategy = 0;  /* favor or force Huffman coding*/
+
+  this.good_match = 0;
+  /* Use a faster search when the previous match is longer than this */
+
+  this.nice_match = 0; /* Stop searching when current match exceeds this */
+
+              /* used by trees.c: */
+
+  /* Didn't use ct_data typedef below to suppress compiler warning */
+
+  // struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+  // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+  // struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+  // Use flat array of DOUBLE size, with interleaved fata,
+  // because JS does not support effective
+  this.dyn_ltree  = new utils.Buf16(HEAP_SIZE * 2);
+  this.dyn_dtree  = new utils.Buf16((2 * D_CODES + 1) * 2);
+  this.bl_tree    = new utils.Buf16((2 * BL_CODES + 1) * 2);
+  zero(this.dyn_ltree);
+  zero(this.dyn_dtree);
+  zero(this.bl_tree);
+
+  this.l_desc   = null;         /* desc. for literal tree */
+  this.d_desc   = null;         /* desc. for distance tree */
+  this.bl_desc  = null;         /* desc. for bit length tree */
+
+  //ush bl_count[MAX_BITS+1];
+  this.bl_count = new utils.Buf16(MAX_BITS + 1);
+  /* number of codes at each bit length for an optimal tree */
+
+  //int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+  this.heap = new utils.Buf16(2 * L_CODES + 1);  /* heap used to build the Huffman trees */
+  zero(this.heap);
+
+  this.heap_len = 0;               /* number of elements in the heap */
+  this.heap_max = 0;               /* element of largest frequency */
+  /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+   * The same heap array is used to build all trees.
+   */
+
+  this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1];
+  zero(this.depth);
+  /* Depth of each subtree used as tie breaker for trees of equal frequency
+   */
+
+  this.l_buf = 0;          /* buffer index for literals or lengths */
+
+  this.lit_bufsize = 0;
+  /* Size of match buffer for literals/lengths.  There are 4 reasons for
+   * limiting lit_bufsize to 64K:
+   *   - frequencies can be kept in 16 bit counters
+   *   - if compression is not successful for the first block, all input
+   *     data is still in the window so we can still emit a stored block even
+   *     when input comes from standard input.  (This can also be done for
+   *     all blocks if lit_bufsize is not greater than 32K.)
+   *   - if compression is not successful for a file smaller than 64K, we can
+   *     even emit a stored file instead of a stored block (saving 5 bytes).
+   *     This is applicable only for zip (not gzip or zlib).
+   *   - creating new Huffman trees less frequently may not provide fast
+   *     adaptation to changes in the input data statistics. (Take for
+   *     example a binary file with poorly compressible code followed by
+   *     a highly compressible string table.) Smaller buffer sizes give
+   *     fast adaptation but have of course the overhead of transmitting
+   *     trees more frequently.
+   *   - I can't count above 4
+   */
+
+  this.last_lit = 0;      /* running index in l_buf */
+
+  this.d_buf = 0;
+  /* Buffer index for distances. To simplify the code, d_buf and l_buf have
+   * the same number of elements. To use different lengths, an extra flag
+   * array would be necessary.
+   */
+
+  this.opt_len = 0;       /* bit length of current block with optimal trees */
+  this.static_len = 0;    /* bit length of current block with static trees */
+  this.matches = 0;       /* number of string matches in current block */
+  this.insert = 0;        /* bytes at end of window left to insert */
+
+
+  this.bi_buf = 0;
+  /* Output buffer. bits are inserted starting at the bottom (least
+   * significant bits).
+   */
+  this.bi_valid = 0;
+  /* Number of valid bits in bi_buf.  All bits above the last valid bit
+   * are always zero.
+   */
+
+  // Used for window memory init. We safely ignore it for JS. That makes
+  // sense only for pointers and memory check tools.
+  //this.high_water = 0;
+  /* High water mark offset in window for initialized bytes -- bytes above
+   * this are set to zero in order to avoid memory check warnings when
+   * longest match routines access bytes past the input.  This is then
+   * updated to the new high water mark.
+   */
+}
+
+
+function deflateResetKeep(strm) {
+  var s;
+
+  if (!strm || !strm.state) {
+    return err(strm, Z_STREAM_ERROR);
+  }
+
+  strm.total_in = strm.total_out = 0;
+  strm.data_type = Z_UNKNOWN;
+
+  s = strm.state;
+  s.pending = 0;
+  s.pending_out = 0;
+
+  if (s.wrap < 0) {
+    s.wrap = -s.wrap;
+    /* was made negative by deflate(..., Z_FINISH); */
+  }
+  s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
+  strm.adler = (s.wrap === 2) ?
+    0  // crc32(0, Z_NULL, 0)
+  :
+    1; // adler32(0, Z_NULL, 0)
+  s.last_flush = Z_NO_FLUSH;
+  trees._tr_init(s);
+  return Z_OK;
+}
+
+
+function deflateReset(strm) {
+  var ret = deflateResetKeep(strm);
+  if (ret === Z_OK) {
+    lm_init(strm.state);
+  }
+  return ret;
+}
+
+
+function deflateSetHeader(strm, head) {
+  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+  if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
+  strm.state.gzhead = head;
+  return Z_OK;
+}
+
+
+function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
+  if (!strm) { // === Z_NULL
+    return Z_STREAM_ERROR;
+  }
+  var wrap = 1;
+
+  if (level === Z_DEFAULT_COMPRESSION) {
+    level = 6;
+  }
+
+  if (windowBits < 0) { /* suppress zlib wrapper */
+    wrap = 0;
+    windowBits = -windowBits;
+  }
+
+  else if (windowBits > 15) {
+    wrap = 2;           /* write gzip wrapper instead */
+    windowBits -= 16;
+  }
+
+
+  if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
+    windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+    strategy < 0 || strategy > Z_FIXED) {
+    return err(strm, Z_STREAM_ERROR);
+  }
+
+
+  if (windowBits === 8) {
+    windowBits = 9;
+  }
+  /* until 256-byte window bug fixed */
+
+  var s = new DeflateState();
+
+  strm.state = s;
+  s.strm = strm;
+
+  s.wrap = wrap;
+  s.gzhead = null;
+  s.w_bits = windowBits;
+  s.w_size = 1 << s.w_bits;
+  s.w_mask = s.w_size - 1;
+
+  s.hash_bits = memLevel + 7;
+  s.hash_size = 1 << s.hash_bits;
+  s.hash_mask = s.hash_size - 1;
+  s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
+
+  s.window = new utils.Buf8(s.w_size * 2);
+  s.head = new utils.Buf16(s.hash_size);
+  s.prev = new utils.Buf16(s.w_size);
+
+  // Don't need mem init magic for JS.
+  //s.high_water = 0;  /* nothing written to s->window yet */
+
+  s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+  s.pending_buf_size = s.lit_bufsize * 4;
+
+  //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+  //s->pending_buf = (uchf *) overlay;
+  s.pending_buf = new utils.Buf8(s.pending_buf_size);
+
+  // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
+  //s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+  s.d_buf = 1 * s.lit_bufsize;
+
+  //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+  s.l_buf = (1 + 2) * s.lit_bufsize;
+
+  s.level = level;
+  s.strategy = strategy;
+  s.method = method;
+
+  return deflateReset(strm);
+}
+
+function deflateInit(strm, level) {
+  return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+}
+
+
+function deflate(strm, flush) {
+  var old_flush, s;
+  var beg, val; // for gzip header write only
+
+  if (!strm || !strm.state ||
+    flush > Z_BLOCK || flush < 0) {
+    return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
+  }
+
+  s = strm.state;
+
+  if (!strm.output ||
+      (!strm.input && strm.avail_in !== 0) ||
+      (s.status === FINISH_STATE && flush !== Z_FINISH)) {
+    return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
+  }
+
+  s.strm = strm; /* just in case */
+  old_flush = s.last_flush;
+  s.last_flush = flush;
+
+  /* Write the header */
+  if (s.status === INIT_STATE) {
+
+    if (s.wrap === 2) { // GZIP header
+      strm.adler = 0;  //crc32(0L, Z_NULL, 0);
+      put_byte(s, 31);
+      put_byte(s, 139);
+      put_byte(s, 8);
+      if (!s.gzhead) { // s->gzhead == Z_NULL
+        put_byte(s, 0);
+        put_byte(s, 0);
+        put_byte(s, 0);
+        put_byte(s, 0);
+        put_byte(s, 0);
+        put_byte(s, s.level === 9 ? 2 :
+                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
+                     4 : 0));
+        put_byte(s, OS_CODE);
+        s.status = BUSY_STATE;
+      }
+      else {
+        put_byte(s, (s.gzhead.text ? 1 : 0) +
+                    (s.gzhead.hcrc ? 2 : 0) +
+                    (!s.gzhead.extra ? 0 : 4) +
+                    (!s.gzhead.name ? 0 : 8) +
+                    (!s.gzhead.comment ? 0 : 16)
+                );
+        put_byte(s, s.gzhead.time & 0xff);
+        put_byte(s, (s.gzhead.time >> 8) & 0xff);
+        put_byte(s, (s.gzhead.time >> 16) & 0xff);
+        put_byte(s, (s.gzhead.time >> 24) & 0xff);
+        put_byte(s, s.level === 9 ? 2 :
+                    (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
+                     4 : 0));
+        put_byte(s, s.gzhead.os & 0xff);
+        if (s.gzhead.extra && s.gzhead.extra.length) {
+          put_byte(s, s.gzhead.extra.length & 0xff);
+          put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
+        }
+        if (s.gzhead.hcrc) {
+          strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
+        }
+        s.gzindex = 0;
+        s.status = EXTRA_STATE;
+      }
+    }
+    else // DEFLATE header
+    {
+      var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
+      var level_flags = -1;
+
+      if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
+        level_flags = 0;
+      } else if (s.level < 6) {
+        level_flags = 1;
+      } else if (s.level === 6) {
+        level_flags = 2;
+      } else {
+        level_flags = 3;
+      }
+      header |= (level_flags << 6);
+      if (s.strstart !== 0) { header |= PRESET_DICT; }
+      header += 31 - (header % 31);
+
+      s.status = BUSY_STATE;
+      putShortMSB(s, header);
+
+      /* Save the adler32 of the preset dictionary: */
+      if (s.strstart !== 0) {
+        putShortMSB(s, strm.adler >>> 16);
+        putShortMSB(s, strm.adler & 0xffff);
+      }
+      strm.adler = 1; // adler32(0L, Z_NULL, 0);
+    }
+  }
+
+//#ifdef GZIP
+  if (s.status === EXTRA_STATE) {
+    if (s.gzhead.extra/* != Z_NULL*/) {
+      beg = s.pending;  /* start of bytes to update crc */
+
+      while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
+        if (s.pending === s.pending_buf_size) {
+          if (s.gzhead.hcrc && s.pending > beg) {
+            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+          }
+          flush_pending(strm);
+          beg = s.pending;
+          if (s.pending === s.pending_buf_size) {
+            break;
+          }
+        }
+        put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
+        s.gzindex++;
+      }
+      if (s.gzhead.hcrc && s.pending > beg) {
+        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+      }
+      if (s.gzindex === s.gzhead.extra.length) {
+        s.gzindex = 0;
+        s.status = NAME_STATE;
+      }
+    }
+    else {
+      s.status = NAME_STATE;
+    }
+  }
+  if (s.status === NAME_STATE) {
+    if (s.gzhead.name/* != Z_NULL*/) {
+      beg = s.pending;  /* start of bytes to update crc */
+      //int val;
+
+      do {
+        if (s.pending === s.pending_buf_size) {
+          if (s.gzhead.hcrc && s.pending > beg) {
+            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+          }
+          flush_pending(strm);
+          beg = s.pending;
+          if (s.pending === s.pending_buf_size) {
+            val = 1;
+            break;
+          }
+        }
+        // JS specific: little magic to add zero terminator to end of string
+        if (s.gzindex < s.gzhead.name.length) {
+          val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
+        } else {
+          val = 0;
+        }
+        put_byte(s, val);
+      } while (val !== 0);
+
+      if (s.gzhead.hcrc && s.pending > beg) {
+        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+      }
+      if (val === 0) {
+        s.gzindex = 0;
+        s.status = COMMENT_STATE;
+      }
+    }
+    else {
+      s.status = COMMENT_STATE;
+    }
+  }
+  if (s.status === COMMENT_STATE) {
+    if (s.gzhead.comment/* != Z_NULL*/) {
+      beg = s.pending;  /* start of bytes to update crc */
+      //int val;
+
+      do {
+        if (s.pending === s.pending_buf_size) {
+          if (s.gzhead.hcrc && s.pending > beg) {
+            strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+          }
+          flush_pending(strm);
+          beg = s.pending;
+          if (s.pending === s.pending_buf_size) {
+            val = 1;
+            break;
+          }
+        }
+        // JS specific: little magic to add zero terminator to end of string
+        if (s.gzindex < s.gzhead.comment.length) {
+          val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
+        } else {
+          val = 0;
+        }
+        put_byte(s, val);
+      } while (val !== 0);
+
+      if (s.gzhead.hcrc && s.pending > beg) {
+        strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
+      }
+      if (val === 0) {
+        s.status = HCRC_STATE;
+      }
+    }
+    else {
+      s.status = HCRC_STATE;
+    }
+  }
+  if (s.status === HCRC_STATE) {
+    if (s.gzhead.hcrc) {
+      if (s.pending + 2 > s.pending_buf_size) {
+        flush_pending(strm);
+      }
+      if (s.pending + 2 <= s.pending_buf_size) {
+        put_byte(s, strm.adler & 0xff);
+        put_byte(s, (strm.adler >> 8) & 0xff);
+        strm.adler = 0; //crc32(0L, Z_NULL, 0);
+        s.status = BUSY_STATE;
+      }
+    }
+    else {
+      s.status = BUSY_STATE;
+    }
+  }
+//#endif
+
+  /* Flush as much pending output as possible */
+  if (s.pending !== 0) {
+    flush_pending(strm);
+    if (strm.avail_out === 0) {
+      /* Since avail_out is 0, deflate will be called again with
+       * more output space, but possibly with both pending and
+       * avail_in equal to zero. There won't be anything to do,
+       * but this is not an error situation so make sure we
+       * return OK instead of BUF_ERROR at next call of deflate:
+       */
+      s.last_flush = -1;
+      return Z_OK;
+    }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+  } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
+    flush !== Z_FINISH) {
+    return err(strm, Z_BUF_ERROR);
+  }
+
+  /* User must not provide more input after the first FINISH: */
+  if (s.status === FINISH_STATE && strm.avail_in !== 0) {
+    return err(strm, Z_BUF_ERROR);
+  }
+
+  /* Start a new block or continue the current one.
+   */
+  if (strm.avail_in !== 0 || s.lookahead !== 0 ||
+    (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
+    var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
+      (s.strategy === Z_RLE ? deflate_rle(s, flush) :
+        configuration_table[s.level].func(s, flush));
+
+    if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
+      s.status = FINISH_STATE;
+    }
+    if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
+      if (strm.avail_out === 0) {
+        s.last_flush = -1;
+        /* avoid BUF_ERROR next call, see above */
+      }
+      return Z_OK;
+      /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+       * of deflate should use the same flush parameter to make sure
+       * that the flush is complete. So we don't have to output an
+       * empty block here, this will be done at next call. This also
+       * ensures that for a very small output buffer, we emit at most
+       * one empty block.
+       */
+    }
+    if (bstate === BS_BLOCK_DONE) {
+      if (flush === Z_PARTIAL_FLUSH) {
+        trees._tr_align(s);
+      }
+      else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+
+        trees._tr_stored_block(s, 0, 0, false);
+        /* For a full flush, this empty block will be recognized
+         * as a special marker by inflate_sync().
+         */
+        if (flush === Z_FULL_FLUSH) {
+          /*** CLEAR_HASH(s); ***/             /* forget history */
+          zero(s.head); // Fill with NIL (= 0);
+
+          if (s.lookahead === 0) {
+            s.strstart = 0;
+            s.block_start = 0;
+            s.insert = 0;
+          }
+        }
+      }
+      flush_pending(strm);
+      if (strm.avail_out === 0) {
+        s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+        return Z_OK;
+      }
+    }
+  }
+  //Assert(strm->avail_out > 0, "bug2");
+  //if (strm.avail_out <= 0) { throw new Error("bug2");}
+
+  if (flush !== Z_FINISH) { return Z_OK; }
+  if (s.wrap <= 0) { return Z_STREAM_END; }
+
+  /* Write the trailer */
+  if (s.wrap === 2) {
+    put_byte(s, strm.adler & 0xff);
+    put_byte(s, (strm.adler >> 8) & 0xff);
+    put_byte(s, (strm.adler >> 16) & 0xff);
+    put_byte(s, (strm.adler >> 24) & 0xff);
+    put_byte(s, strm.total_in & 0xff);
+    put_byte(s, (strm.total_in >> 8) & 0xff);
+    put_byte(s, (strm.total_in >> 16) & 0xff);
+    put_byte(s, (strm.total_in >> 24) & 0xff);
+  }
+  else
+  {
+    putShortMSB(s, strm.adler >>> 16);
+    putShortMSB(s, strm.adler & 0xffff);
+  }
+
+  flush_pending(strm);
+  /* If avail_out is zero, the application will call deflate again
+   * to flush the rest.
+   */
+  if (s.wrap > 0) { s.wrap = -s.wrap; }
+  /* write the trailer only once! */
+  return s.pending !== 0 ? Z_OK : Z_STREAM_END;
+}
+
+function deflateEnd(strm) {
+  var status;
+
+  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
+    return Z_STREAM_ERROR;
+  }
+
+  status = strm.state.status;
+  if (status !== INIT_STATE &&
+    status !== EXTRA_STATE &&
+    status !== NAME_STATE &&
+    status !== COMMENT_STATE &&
+    status !== HCRC_STATE &&
+    status !== BUSY_STATE &&
+    status !== FINISH_STATE
+  ) {
+    return err(strm, Z_STREAM_ERROR);
+  }
+
+  strm.state = null;
+
+  return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
+}
+
+
+/* =========================================================================
+ * Initializes the compression dictionary from the given byte
+ * sequence without producing any compressed output.
+ */
+function deflateSetDictionary(strm, dictionary) {
+  var dictLength = dictionary.length;
+
+  var s;
+  var str, n;
+  var wrap;
+  var avail;
+  var next;
+  var input;
+  var tmpDict;
+
+  if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
+    return Z_STREAM_ERROR;
+  }
+
+  s = strm.state;
+  wrap = s.wrap;
+
+  if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
+    return Z_STREAM_ERROR;
+  }
+
+  /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+  if (wrap === 1) {
+    /* adler32(strm->adler, dictionary, dictLength); */
+    strm.adler = adler32(strm.adler, dictionary, dictLength, 0);
+  }
+
+  s.wrap = 0;   /* avoid computing Adler-32 in read_buf */
+
+  /* if dictionary would fill window, just replace the history */
+  if (dictLength >= s.w_size) {
+    if (wrap === 0) {            /* already empty otherwise */
+      /*** CLEAR_HASH(s); ***/
+      zero(s.head); // Fill with NIL (= 0);
+      s.strstart = 0;
+      s.block_start = 0;
+      s.insert = 0;
+    }
+    /* use the tail */
+    // dictionary = dictionary.slice(dictLength - s.w_size);
+    tmpDict = new utils.Buf8(s.w_size);
+    utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);
+    dictionary = tmpDict;
+    dictLength = s.w_size;
+  }
+  /* insert dictionary into window and hash */
+  avail = strm.avail_in;
+  next = strm.next_in;
+  input = strm.input;
+  strm.avail_in = dictLength;
+  strm.next_in = 0;
+  strm.input = dictionary;
+  fill_window(s);
+  while (s.lookahead >= MIN_MATCH) {
+    str = s.strstart;
+    n = s.lookahead - (MIN_MATCH - 1);
+    do {
+      /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
+      s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask;
+
+      s.prev[str & s.w_mask] = s.head[s.ins_h];
+
+      s.head[s.ins_h] = str;
+      str++;
+    } while (--n);
+    s.strstart = str;
+    s.lookahead = MIN_MATCH - 1;
+    fill_window(s);
+  }
+  s.strstart += s.lookahead;
+  s.block_start = s.strstart;
+  s.insert = s.lookahead;
+  s.lookahead = 0;
+  s.match_length = s.prev_length = MIN_MATCH - 1;
+  s.match_available = 0;
+  strm.next_in = next;
+  strm.input = input;
+  strm.avail_in = avail;
+  s.wrap = wrap;
+  return Z_OK;
+}
+
+
+exports.deflateInit = deflateInit;
+exports.deflateInit2 = deflateInit2;
+exports.deflateReset = deflateReset;
+exports.deflateResetKeep = deflateResetKeep;
+exports.deflateSetHeader = deflateSetHeader;
+exports.deflate = deflate;
+exports.deflateEnd = deflateEnd;
+exports.deflateSetDictionary = deflateSetDictionary;
+exports.deflateInfo = 'pako deflate (from Nodeca project)';
+
+/* Not implemented
+exports.deflateBound = deflateBound;
+exports.deflateCopy = deflateCopy;
+exports.deflateParams = deflateParams;
+exports.deflatePending = deflatePending;
+exports.deflatePrime = deflatePrime;
+exports.deflateTune = deflateTune;
+*/
+
+},{"../utils/common":41,"./adler32":43,"./crc32":45,"./messages":51,"./trees":52}],47:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+function GZheader() {
+  /* true if compressed data believed to be text */
+  this.text       = 0;
+  /* modification time */
+  this.time       = 0;
+  /* extra flags (not used when writing a gzip file) */
+  this.xflags     = 0;
+  /* operating system */
+  this.os         = 0;
+  /* pointer to extra field or Z_NULL if none */
+  this.extra      = null;
+  /* extra field length (valid if extra != Z_NULL) */
+  this.extra_len  = 0; // Actually, we don't need it in JS,
+                       // but leave for few code modifications
+
+  //
+  // Setup limits is not necessary because in js we should not preallocate memory
+  // for inflate use constant limit in 65536 bytes
+  //
+
+  /* space at extra (only when reading header) */
+  // this.extra_max  = 0;
+  /* pointer to zero-terminated file name or Z_NULL */
+  this.name       = '';
+  /* space at name (only when reading header) */
+  // this.name_max   = 0;
+  /* pointer to zero-terminated comment or Z_NULL */
+  this.comment    = '';
+  /* space at comment (only when reading header) */
+  // this.comm_max   = 0;
+  /* true if there was or will be a header crc */
+  this.hcrc       = 0;
+  /* true when done reading gzip header (not used when writing a gzip file) */
+  this.done       = false;
+}
+
+module.exports = GZheader;
+
+},{}],48:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+// See state defs from inflate.js
+var BAD = 30;       /* got a data error -- remain here until reset */
+var TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state.mode === LEN
+        strm.avail_in >= 6
+        strm.avail_out >= 258
+        start >= strm.avail_out
+        state.bits < 8
+
+   On return, state.mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm.avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm.avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+module.exports = function inflate_fast(strm, start) {
+  var state;
+  var _in;                    /* local strm.input */
+  var last;                   /* have enough input while in < last */
+  var _out;                   /* local strm.output */
+  var beg;                    /* inflate()'s initial strm.output */
+  var end;                    /* while out < end, enough space available */
+//#ifdef INFLATE_STRICT
+  var dmax;                   /* maximum distance from zlib header */
+//#endif
+  var wsize;                  /* window size or zero if not using window */
+  var whave;                  /* valid bytes in the window */
+  var wnext;                  /* window write index */
+  // Use `s_window` instead `window`, avoid conflict with instrumentation tools
+  var s_window;               /* allocated sliding window, if wsize != 0 */
+  var hold;                   /* local strm.hold */
+  var bits;                   /* local strm.bits */
+  var lcode;                  /* local strm.lencode */
+  var dcode;                  /* local strm.distcode */
+  var lmask;                  /* mask for first level of length codes */
+  var dmask;                  /* mask for first level of distance codes */
+  var here;                   /* retrieved table entry */
+  var op;                     /* code bits, operation, extra bits, or */
+                              /*  window position, window bytes to copy */
+  var len;                    /* match length, unused bytes */
+  var dist;                   /* match distance */
+  var from;                   /* where to copy match from */
+  var from_source;
+
+
+  var input, output; // JS specific, because we have no pointers
+
+  /* copy state to local variables */
+  state = strm.state;
+  //here = state.here;
+  _in = strm.next_in;
+  input = strm.input;
+  last = _in + (strm.avail_in - 5);
+  _out = strm.next_out;
+  output = strm.output;
+  beg = _out - (start - strm.avail_out);
+  end = _out + (strm.avail_out - 257);
+//#ifdef INFLATE_STRICT
+  dmax = state.dmax;
+//#endif
+  wsize = state.wsize;
+  whave = state.whave;
+  wnext = state.wnext;
+  s_window = state.window;
+  hold = state.hold;
+  bits = state.bits;
+  lcode = state.lencode;
+  dcode = state.distcode;
+  lmask = (1 << state.lenbits) - 1;
+  dmask = (1 << state.distbits) - 1;
+
+
+  /* decode literals and length/distances until end-of-block or not enough
+     input data or output space */
+
+  top:
+  do {
+    if (bits < 15) {
+      hold += input[_in++] << bits;
+      bits += 8;
+      hold += input[_in++] << bits;
+      bits += 8;
+    }
+
+    here = lcode[hold & lmask];
+
+    dolen:
+    for (;;) { // Goto emulation
+      op = here >>> 24/*here.bits*/;
+      hold >>>= op;
+      bits -= op;
+      op = (here >>> 16) & 0xff/*here.op*/;
+      if (op === 0) {                          /* literal */
+        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+        //        "inflate:         literal '%c'\n" :
+        //        "inflate:         literal 0x%02x\n", here.val));
+        output[_out++] = here & 0xffff/*here.val*/;
+      }
+      else if (op & 16) {                     /* length base */
+        len = here & 0xffff/*here.val*/;
+        op &= 15;                           /* number of extra bits */
+        if (op) {
+          if (bits < op) {
+            hold += input[_in++] << bits;
+            bits += 8;
+          }
+          len += hold & ((1 << op) - 1);
+          hold >>>= op;
+          bits -= op;
+        }
+        //Tracevv((stderr, "inflate:         length %u\n", len));
+        if (bits < 15) {
+          hold += input[_in++] << bits;
+          bits += 8;
+          hold += input[_in++] << bits;
+          bits += 8;
+        }
+        here = dcode[hold & dmask];
+
+        dodist:
+        for (;;) { // goto emulation
+          op = here >>> 24/*here.bits*/;
+          hold >>>= op;
+          bits -= op;
+          op = (here >>> 16) & 0xff/*here.op*/;
+
+          if (op & 16) {                      /* distance base */
+            dist = here & 0xffff/*here.val*/;
+            op &= 15;                       /* number of extra bits */
+            if (bits < op) {
+              hold += input[_in++] << bits;
+              bits += 8;
+              if (bits < op) {
+                hold += input[_in++] << bits;
+                bits += 8;
+              }
+            }
+            dist += hold & ((1 << op) - 1);
+//#ifdef INFLATE_STRICT
+            if (dist > dmax) {
+              strm.msg = 'invalid distance too far back';
+              state.mode = BAD;
+              break top;
+            }
+//#endif
+            hold >>>= op;
+            bits -= op;
+            //Tracevv((stderr, "inflate:         distance %u\n", dist));
+            op = _out - beg;                /* max distance in output */
+            if (dist > op) {                /* see if copy from window */
+              op = dist - op;               /* distance back in window */
+              if (op > whave) {
+                if (state.sane) {
+                  strm.msg = 'invalid distance too far back';
+                  state.mode = BAD;
+                  break top;
+                }
+
+// (!) This block is disabled in zlib defailts,
+// don't enable it for binary compatibility
+//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+//                if (len <= op - whave) {
+//                  do {
+//                    output[_out++] = 0;
+//                  } while (--len);
+//                  continue top;
+//                }
+//                len -= op - whave;
+//                do {
+//                  output[_out++] = 0;
+//                } while (--op > whave);
+//                if (op === 0) {
+//                  from = _out - dist;
+//                  do {
+//                    output[_out++] = output[from++];
+//                  } while (--len);
+//                  continue top;
+//                }
+//#endif
+              }
+              from = 0; // window index
+              from_source = s_window;
+              if (wnext === 0) {           /* very common case */
+                from += wsize - op;
+                if (op < len) {         /* some from window */
+                  len -= op;
+                  do {
+                    output[_out++] = s_window[from++];
+                  } while (--op);
+                  from = _out - dist;  /* rest from output */
+                  from_source = output;
+                }
+              }
+              else if (wnext < op) {      /* wrap around window */
+                from += wsize + wnext - op;
+                op -= wnext;
+                if (op < len) {         /* some from end of window */
+                  len -= op;
+                  do {
+                    output[_out++] = s_window[from++];
+                  } while (--op);
+                  from = 0;
+                  if (wnext < len) {  /* some from start of window */
+                    op = wnext;
+                    len -= op;
+                    do {
+                      output[_out++] = s_window[from++];
+                    } while (--op);
+                    from = _out - dist;      /* rest from output */
+                    from_source = output;
+                  }
+                }
+              }
+              else {                      /* contiguous in window */
+                from += wnext - op;
+                if (op < len) {         /* some from window */
+                  len -= op;
+                  do {
+                    output[_out++] = s_window[from++];
+                  } while (--op);
+                  from = _out - dist;  /* rest from output */
+                  from_source = output;
+                }
+              }
+              while (len > 2) {
+                output[_out++] = from_source[from++];
+                output[_out++] = from_source[from++];
+                output[_out++] = from_source[from++];
+                len -= 3;
+              }
+              if (len) {
+                output[_out++] = from_source[from++];
+                if (len > 1) {
+                  output[_out++] = from_source[from++];
+                }
+              }
+            }
+            else {
+              from = _out - dist;          /* copy direct from output */
+              do {                        /* minimum length is three */
+                output[_out++] = output[from++];
+                output[_out++] = output[from++];
+                output[_out++] = output[from++];
+                len -= 3;
+              } while (len > 2);
+              if (len) {
+                output[_out++] = output[from++];
+                if (len > 1) {
+                  output[_out++] = output[from++];
+                }
+              }
+            }
+          }
+          else if ((op & 64) === 0) {          /* 2nd level distance code */
+            here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
+            continue dodist;
+          }
+          else {
+            strm.msg = 'invalid distance code';
+            state.mode = BAD;
+            break top;
+          }
+
+          break; // need to emulate goto via "continue"
+        }
+      }
+      else if ((op & 64) === 0) {              /* 2nd level length code */
+        here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
+        continue dolen;
+      }
+      else if (op & 32) {                     /* end-of-block */
+        //Tracevv((stderr, "inflate:         end of block\n"));
+        state.mode = TYPE;
+        break top;
+      }
+      else {
+        strm.msg = 'invalid literal/length code';
+        state.mode = BAD;
+        break top;
+      }
+
+      break; // need to emulate goto via "continue"
+    }
+  } while (_in < last && _out < end);
+
+  /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+  len = bits >> 3;
+  _in -= len;
+  bits -= len << 3;
+  hold &= (1 << bits) - 1;
+
+  /* update state and return */
+  strm.next_in = _in;
+  strm.next_out = _out;
+  strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
+  strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
+  state.hold = hold;
+  state.bits = bits;
+  return;
+};
+
+},{}],49:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+var utils         = require('../utils/common');
+var adler32       = require('./adler32');
+var crc32         = require('./crc32');
+var inflate_fast  = require('./inffast');
+var inflate_table = require('./inftrees');
+
+var CODES = 0;
+var LENS = 1;
+var DISTS = 2;
+
+/* Public constants ==========================================================*/
+/* ===========================================================================*/
+
+
+/* Allowed flush values; see deflate() and inflate() below for details */
+//var Z_NO_FLUSH      = 0;
+//var Z_PARTIAL_FLUSH = 1;
+//var Z_SYNC_FLUSH    = 2;
+//var Z_FULL_FLUSH    = 3;
+var Z_FINISH        = 4;
+var Z_BLOCK         = 5;
+var Z_TREES         = 6;
+
+
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+var Z_OK            = 0;
+var Z_STREAM_END    = 1;
+var Z_NEED_DICT     = 2;
+//var Z_ERRNO         = -1;
+var Z_STREAM_ERROR  = -2;
+var Z_DATA_ERROR    = -3;
+var Z_MEM_ERROR     = -4;
+var Z_BUF_ERROR     = -5;
+//var Z_VERSION_ERROR = -6;
+
+/* The deflate compression method */
+var Z_DEFLATED  = 8;
+
+
+/* STATES ====================================================================*/
+/* ===========================================================================*/
+
+
+var    HEAD = 1;       /* i: waiting for magic header */
+var    FLAGS = 2;      /* i: waiting for method and flags (gzip) */
+var    TIME = 3;       /* i: waiting for modification time (gzip) */
+var    OS = 4;         /* i: waiting for extra flags and operating system (gzip) */
+var    EXLEN = 5;      /* i: waiting for extra length (gzip) */
+var    EXTRA = 6;      /* i: waiting for extra bytes (gzip) */
+var    NAME = 7;       /* i: waiting for end of file name (gzip) */
+var    COMMENT = 8;    /* i: waiting for end of comment (gzip) */
+var    HCRC = 9;       /* i: waiting for header crc (gzip) */
+var    DICTID = 10;    /* i: waiting for dictionary check value */
+var    DICT = 11;      /* waiting for inflateSetDictionary() call */
+var        TYPE = 12;      /* i: waiting for type bits, including last-flag bit */
+var        TYPEDO = 13;    /* i: same, but skip check to exit inflate on new block */
+var        STORED = 14;    /* i: waiting for stored size (length and complement) */
+var        COPY_ = 15;     /* i/o: same as COPY below, but only first time in */
+var        COPY = 16;      /* i/o: waiting for input or output to copy stored block */
+var        TABLE = 17;     /* i: waiting for dynamic block table lengths */
+var        LENLENS = 18;   /* i: waiting for code length code lengths */
+var        CODELENS = 19;  /* i: waiting for length/lit and distance code lengths */
+var            LEN_ = 20;      /* i: same as LEN below, but only first time in */
+var            LEN = 21;       /* i: waiting for length/lit/eob code */
+var            LENEXT = 22;    /* i: waiting for length extra bits */
+var            DIST = 23;      /* i: waiting for distance code */
+var            DISTEXT = 24;   /* i: waiting for distance extra bits */
+var            MATCH = 25;     /* o: waiting for output space to copy string */
+var            LIT = 26;       /* o: waiting for output space to write literal */
+var    CHECK = 27;     /* i: waiting for 32-bit check value */
+var    LENGTH = 28;    /* i: waiting for 32-bit length (gzip) */
+var    DONE = 29;      /* finished check, done -- remain here until reset */
+var    BAD = 30;       /* got a data error -- remain here until reset */
+var    MEM = 31;       /* got an inflate() memory error -- remain here until reset */
+var    SYNC = 32;      /* looking for synchronization bytes to restart inflate() */
+
+/* ===========================================================================*/
+
+
+
+var ENOUGH_LENS = 852;
+var ENOUGH_DISTS = 592;
+//var ENOUGH =  (ENOUGH_LENS+ENOUGH_DISTS);
+
+var MAX_WBITS = 15;
+/* 32K LZ77 window */
+var DEF_WBITS = MAX_WBITS;
+
+
+function zswap32(q) {
+  return  (((q >>> 24) & 0xff) +
+          ((q >>> 8) & 0xff00) +
+          ((q & 0xff00) << 8) +
+          ((q & 0xff) << 24));
+}
+
+
+function InflateState() {
+  this.mode = 0;             /* current inflate mode */
+  this.last = false;          /* true if processing last block */
+  this.wrap = 0;              /* bit 0 true for zlib, bit 1 true for gzip */
+  this.havedict = false;      /* true if dictionary provided */
+  this.flags = 0;             /* gzip header method and flags (0 if zlib) */
+  this.dmax = 0;              /* zlib header max distance (INFLATE_STRICT) */
+  this.check = 0;             /* protected copy of check value */
+  this.total = 0;             /* protected copy of output count */
+  // TODO: may be {}
+  this.head = null;           /* where to save gzip header information */
+
+  /* sliding window */
+  this.wbits = 0;             /* log base 2 of requested window size */
+  this.wsize = 0;             /* window size or zero if not using window */
+  this.whave = 0;             /* valid bytes in the window */
+  this.wnext = 0;             /* window write index */
+  this.window = null;         /* allocated sliding window, if needed */
+
+  /* bit accumulator */
+  this.hold = 0;              /* input bit accumulator */
+  this.bits = 0;              /* number of bits in "in" */
+
+  /* for string and stored block copying */
+  this.length = 0;            /* literal or length of data to copy */
+  this.offset = 0;            /* distance back to copy string from */
+
+  /* for table and code decoding */
+  this.extra = 0;             /* extra bits needed */
+
+  /* fixed and dynamic code tables */
+  this.lencode = null;          /* starting table for length/literal codes */
+  this.distcode = null;         /* starting table for distance codes */
+  this.lenbits = 0;           /* index bits for lencode */
+  this.distbits = 0;          /* index bits for distcode */
+
+  /* dynamic table building */
+  this.ncode = 0;             /* number of code length code lengths */
+  this.nlen = 0;              /* number of length code lengths */
+  this.ndist = 0;             /* number of distance code lengths */
+  this.have = 0;              /* number of code lengths in lens[] */
+  this.next = null;              /* next available space in codes[] */
+
+  this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
+  this.work = new utils.Buf16(288); /* work area for code table building */
+
+  /*
+   because we don't have pointers in js, we use lencode and distcode directly
+   as buffers so we don't need codes
+  */
+  //this.codes = new utils.Buf32(ENOUGH);       /* space for code tables */
+  this.lendyn = null;              /* dynamic table for length/literal codes (JS specific) */
+  this.distdyn = null;             /* dynamic table for distance codes (JS specific) */
+  this.sane = 0;                   /* if false, allow invalid distance too far */
+  this.back = 0;                   /* bits back of last unprocessed length/lit */
+  this.was = 0;                    /* initial length of match */
+}
+
+function inflateResetKeep(strm) {
+  var state;
+
+  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+  state = strm.state;
+  strm.total_in = strm.total_out = state.total = 0;
+  strm.msg = ''; /*Z_NULL*/
+  if (state.wrap) {       /* to support ill-conceived Java test suite */
+    strm.adler = state.wrap & 1;
+  }
+  state.mode = HEAD;
+  state.last = 0;
+  state.havedict = 0;
+  state.dmax = 32768;
+  state.head = null/*Z_NULL*/;
+  state.hold = 0;
+  state.bits = 0;
+  //state.lencode = state.distcode = state.next = state.codes;
+  state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
+  state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
+
+  state.sane = 1;
+  state.back = -1;
+  //Tracev((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+function inflateReset(strm) {
+  var state;
+
+  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+  state = strm.state;
+  state.wsize = 0;
+  state.whave = 0;
+  state.wnext = 0;
+  return inflateResetKeep(strm);
+
+}
+
+function inflateReset2(strm, windowBits) {
+  var wrap;
+  var state;
+
+  /* get the state */
+  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+  state = strm.state;
+
+  /* extract wrap request from windowBits parameter */
+  if (windowBits < 0) {
+    wrap = 0;
+    windowBits = -windowBits;
+  }
+  else {
+    wrap = (windowBits >> 4) + 1;
+    if (windowBits < 48) {
+      windowBits &= 15;
+    }
+  }
+
+  /* set number of window bits, free window if different */
+  if (windowBits && (windowBits < 8 || windowBits > 15)) {
+    return Z_STREAM_ERROR;
+  }
+  if (state.window !== null && state.wbits !== windowBits) {
+    state.window = null;
+  }
+
+  /* update state and reset the rest of it */
+  state.wrap = wrap;
+  state.wbits = windowBits;
+  return inflateReset(strm);
+}
+
+function inflateInit2(strm, windowBits) {
+  var ret;
+  var state;
+
+  if (!strm) { return Z_STREAM_ERROR; }
+  //strm.msg = Z_NULL;                 /* in case we return an error */
+
+  state = new InflateState();
+
+  //if (state === Z_NULL) return Z_MEM_ERROR;
+  //Tracev((stderr, "inflate: allocated\n"));
+  strm.state = state;
+  state.window = null/*Z_NULL*/;
+  ret = inflateReset2(strm, windowBits);
+  if (ret !== Z_OK) {
+    strm.state = null/*Z_NULL*/;
+  }
+  return ret;
+}
+
+function inflateInit(strm) {
+  return inflateInit2(strm, DEF_WBITS);
+}
+
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter.  This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time.  However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+var virgin = true;
+
+var lenfix, distfix; // We have no pointers in JS, so keep tables separate
+
+function fixedtables(state) {
+  /* build fixed huffman tables if first call (may not be thread safe) */
+  if (virgin) {
+    var sym;
+
+    lenfix = new utils.Buf32(512);
+    distfix = new utils.Buf32(32);
+
+    /* literal/length table */
+    sym = 0;
+    while (sym < 144) { state.lens[sym++] = 8; }
+    while (sym < 256) { state.lens[sym++] = 9; }
+    while (sym < 280) { state.lens[sym++] = 7; }
+    while (sym < 288) { state.lens[sym++] = 8; }
+
+    inflate_table(LENS,  state.lens, 0, 288, lenfix,   0, state.work, { bits: 9 });
+
+    /* distance table */
+    sym = 0;
+    while (sym < 32) { state.lens[sym++] = 5; }
+
+    inflate_table(DISTS, state.lens, 0, 32,   distfix, 0, state.work, { bits: 5 });
+
+    /* do this just once */
+    virgin = false;
+  }
+
+  state.lencode = lenfix;
+  state.lenbits = 9;
+  state.distcode = distfix;
+  state.distbits = 5;
+}
+
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning.  If window does not exist yet, create it.  This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+function updatewindow(strm, src, end, copy) {
+  var dist;
+  var state = strm.state;
+
+  /* if it hasn't been done already, allocate space for the window */
+  if (state.window === null) {
+    state.wsize = 1 << state.wbits;
+    state.wnext = 0;
+    state.whave = 0;
+
+    state.window = new utils.Buf8(state.wsize);
+  }
+
+  /* copy state->wsize or less output bytes into the circular window */
+  if (copy >= state.wsize) {
+    utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0);
+    state.wnext = 0;
+    state.whave = state.wsize;
+  }
+  else {
+    dist = state.wsize - state.wnext;
+    if (dist > copy) {
+      dist = copy;
+    }
+    //zmemcpy(state->window + state->wnext, end - copy, dist);
+    utils.arraySet(state.window, src, end - copy, dist, state.wnext);
+    copy -= dist;
+    if (copy) {
+      //zmemcpy(state->window, end - copy, copy);
+      utils.arraySet(state.window, src, end - copy, copy, 0);
+      state.wnext = copy;
+      state.whave = state.wsize;
+    }
+    else {
+      state.wnext += dist;
+      if (state.wnext === state.wsize) { state.wnext = 0; }
+      if (state.whave < state.wsize) { state.whave += dist; }
+    }
+  }
+  return 0;
+}
+
+function inflate(strm, flush) {
+  var state;
+  var input, output;          // input/output buffers
+  var next;                   /* next input INDEX */
+  var put;                    /* next output INDEX */
+  var have, left;             /* available input and output */
+  var hold;                   /* bit buffer */
+  var bits;                   /* bits in bit buffer */
+  var _in, _out;              /* save starting available input and output */
+  var copy;                   /* number of stored or match bytes to copy */
+  var from;                   /* where to copy match bytes from */
+  var from_source;
+  var here = 0;               /* current decoding table entry */
+  var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
+  //var last;                   /* parent table entry */
+  var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
+  var len;                    /* length to copy for repeats, bits to drop */
+  var ret;                    /* return code */
+  var hbuf = new utils.Buf8(4);    /* buffer for gzip header crc calculation */
+  var opts;
+
+  var n; // temporary var for NEED_BITS
+
+  var order = /* permutation of code lengths */
+    [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
+
+
+  if (!strm || !strm.state || !strm.output ||
+      (!strm.input && strm.avail_in !== 0)) {
+    return Z_STREAM_ERROR;
+  }
+
+  state = strm.state;
+  if (state.mode === TYPE) { state.mode = TYPEDO; }    /* skip check */
+
+
+  //--- LOAD() ---
+  put = strm.next_out;
+  output = strm.output;
+  left = strm.avail_out;
+  next = strm.next_in;
+  input = strm.input;
+  have = strm.avail_in;
+  hold = state.hold;
+  bits = state.bits;
+  //---
+
+  _in = have;
+  _out = left;
+  ret = Z_OK;
+
+  inf_leave: // goto emulation
+  for (;;) {
+    switch (state.mode) {
+    case HEAD:
+      if (state.wrap === 0) {
+        state.mode = TYPEDO;
+        break;
+      }
+      //=== NEEDBITS(16);
+      while (bits < 16) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      if ((state.wrap & 2) && hold === 0x8b1f) {  /* gzip header */
+        state.check = 0/*crc32(0L, Z_NULL, 0)*/;
+        //=== CRC2(state.check, hold);
+        hbuf[0] = hold & 0xff;
+        hbuf[1] = (hold >>> 8) & 0xff;
+        state.check = crc32(state.check, hbuf, 2, 0);
+        //===//
+
+        //=== INITBITS();
+        hold = 0;
+        bits = 0;
+        //===//
+        state.mode = FLAGS;
+        break;
+      }
+      state.flags = 0;           /* expect zlib header */
+      if (state.head) {
+        state.head.done = false;
+      }
+      if (!(state.wrap & 1) ||   /* check if zlib header allowed */
+        (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
+        strm.msg = 'incorrect header check';
+        state.mode = BAD;
+        break;
+      }
+      if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
+        strm.msg = 'unknown compression method';
+        state.mode = BAD;
+        break;
+      }
+      //--- DROPBITS(4) ---//
+      hold >>>= 4;
+      bits -= 4;
+      //---//
+      len = (hold & 0x0f)/*BITS(4)*/ + 8;
+      if (state.wbits === 0) {
+        state.wbits = len;
+      }
+      else if (len > state.wbits) {
+        strm.msg = 'invalid window size';
+        state.mode = BAD;
+        break;
+      }
+      state.dmax = 1 << len;
+      //Tracev((stderr, "inflate:   zlib header ok\n"));
+      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
+      state.mode = hold & 0x200 ? DICTID : TYPE;
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      break;
+    case FLAGS:
+      //=== NEEDBITS(16); */
+      while (bits < 16) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      state.flags = hold;
+      if ((state.flags & 0xff) !== Z_DEFLATED) {
+        strm.msg = 'unknown compression method';
+        state.mode = BAD;
+        break;
+      }
+      if (state.flags & 0xe000) {
+        strm.msg = 'unknown header flags set';
+        state.mode = BAD;
+        break;
+      }
+      if (state.head) {
+        state.head.text = ((hold >> 8) & 1);
+      }
+      if (state.flags & 0x0200) {
+        //=== CRC2(state.check, hold);
+        hbuf[0] = hold & 0xff;
+        hbuf[1] = (hold >>> 8) & 0xff;
+        state.check = crc32(state.check, hbuf, 2, 0);
+        //===//
+      }
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      state.mode = TIME;
+      /* falls through */
+    case TIME:
+      //=== NEEDBITS(32); */
+      while (bits < 32) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      if (state.head) {
+        state.head.time = hold;
+      }
+      if (state.flags & 0x0200) {
+        //=== CRC4(state.check, hold)
+        hbuf[0] = hold & 0xff;
+        hbuf[1] = (hold >>> 8) & 0xff;
+        hbuf[2] = (hold >>> 16) & 0xff;
+        hbuf[3] = (hold >>> 24) & 0xff;
+        state.check = crc32(state.check, hbuf, 4, 0);
+        //===
+      }
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      state.mode = OS;
+      /* falls through */
+    case OS:
+      //=== NEEDBITS(16); */
+      while (bits < 16) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      if (state.head) {
+        state.head.xflags = (hold & 0xff);
+        state.head.os = (hold >> 8);
+      }
+      if (state.flags & 0x0200) {
+        //=== CRC2(state.check, hold);
+        hbuf[0] = hold & 0xff;
+        hbuf[1] = (hold >>> 8) & 0xff;
+        state.check = crc32(state.check, hbuf, 2, 0);
+        //===//
+      }
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      state.mode = EXLEN;
+      /* falls through */
+    case EXLEN:
+      if (state.flags & 0x0400) {
+        //=== NEEDBITS(16); */
+        while (bits < 16) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        state.length = hold;
+        if (state.head) {
+          state.head.extra_len = hold;
+        }
+        if (state.flags & 0x0200) {
+          //=== CRC2(state.check, hold);
+          hbuf[0] = hold & 0xff;
+          hbuf[1] = (hold >>> 8) & 0xff;
+          state.check = crc32(state.check, hbuf, 2, 0);
+          //===//
+        }
+        //=== INITBITS();
+        hold = 0;
+        bits = 0;
+        //===//
+      }
+      else if (state.head) {
+        state.head.extra = null/*Z_NULL*/;
+      }
+      state.mode = EXTRA;
+      /* falls through */
+    case EXTRA:
+      if (state.flags & 0x0400) {
+        copy = state.length;
+        if (copy > have) { copy = have; }
+        if (copy) {
+          if (state.head) {
+            len = state.head.extra_len - state.length;
+            if (!state.head.extra) {
+              // Use untyped array for more conveniend processing later
+              state.head.extra = new Array(state.head.extra_len);
+            }
+            utils.arraySet(
+              state.head.extra,
+              input,
+              next,
+              // extra field is limited to 65536 bytes
+              // - no need for additional size check
+              copy,
+              /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
+              len
+            );
+            //zmemcpy(state.head.extra + len, next,
+            //        len + copy > state.head.extra_max ?
+            //        state.head.extra_max - len : copy);
+          }
+          if (state.flags & 0x0200) {
+            state.check = crc32(state.check, input, copy, next);
+          }
+          have -= copy;
+          next += copy;
+          state.length -= copy;
+        }
+        if (state.length) { break inf_leave; }
+      }
+      state.length = 0;
+      state.mode = NAME;
+      /* falls through */
+    case NAME:
+      if (state.flags & 0x0800) {
+        if (have === 0) { break inf_leave; }
+        copy = 0;
+        do {
+          // TODO: 2 or 1 bytes?
+          len = input[next + copy++];
+          /* use constant limit because in js we should not preallocate memory */
+          if (state.head && len &&
+              (state.length < 65536 /*state.head.name_max*/)) {
+            state.head.name += String.fromCharCode(len);
+          }
+        } while (len && copy < have);
+
+        if (state.flags & 0x0200) {
+          state.check = crc32(state.check, input, copy, next);
+        }
+        have -= copy;
+        next += copy;
+        if (len) { break inf_leave; }
+      }
+      else if (state.head) {
+        state.head.name = null;
+      }
+      state.length = 0;
+      state.mode = COMMENT;
+      /* falls through */
+    case COMMENT:
+      if (state.flags & 0x1000) {
+        if (have === 0) { break inf_leave; }
+        copy = 0;
+        do {
+          len = input[next + copy++];
+          /* use constant limit because in js we should not preallocate memory */
+          if (state.head && len &&
+              (state.length < 65536 /*state.head.comm_max*/)) {
+            state.head.comment += String.fromCharCode(len);
+          }
+        } while (len && copy < have);
+        if (state.flags & 0x0200) {
+          state.check = crc32(state.check, input, copy, next);
+        }
+        have -= copy;
+        next += copy;
+        if (len) { break inf_leave; }
+      }
+      else if (state.head) {
+        state.head.comment = null;
+      }
+      state.mode = HCRC;
+      /* falls through */
+    case HCRC:
+      if (state.flags & 0x0200) {
+        //=== NEEDBITS(16); */
+        while (bits < 16) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        if (hold !== (state.check & 0xffff)) {
+          strm.msg = 'header crc mismatch';
+          state.mode = BAD;
+          break;
+        }
+        //=== INITBITS();
+        hold = 0;
+        bits = 0;
+        //===//
+      }
+      if (state.head) {
+        state.head.hcrc = ((state.flags >> 9) & 1);
+        state.head.done = true;
+      }
+      strm.adler = state.check = 0;
+      state.mode = TYPE;
+      break;
+    case DICTID:
+      //=== NEEDBITS(32); */
+      while (bits < 32) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      strm.adler = state.check = zswap32(hold);
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      state.mode = DICT;
+      /* falls through */
+    case DICT:
+      if (state.havedict === 0) {
+        //--- RESTORE() ---
+        strm.next_out = put;
+        strm.avail_out = left;
+        strm.next_in = next;
+        strm.avail_in = have;
+        state.hold = hold;
+        state.bits = bits;
+        //---
+        return Z_NEED_DICT;
+      }
+      strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
+      state.mode = TYPE;
+      /* falls through */
+    case TYPE:
+      if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
+      /* falls through */
+    case TYPEDO:
+      if (state.last) {
+        //--- BYTEBITS() ---//
+        hold >>>= bits & 7;
+        bits -= bits & 7;
+        //---//
+        state.mode = CHECK;
+        break;
+      }
+      //=== NEEDBITS(3); */
+      while (bits < 3) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      state.last = (hold & 0x01)/*BITS(1)*/;
+      //--- DROPBITS(1) ---//
+      hold >>>= 1;
+      bits -= 1;
+      //---//
+
+      switch ((hold & 0x03)/*BITS(2)*/) {
+      case 0:                             /* stored block */
+        //Tracev((stderr, "inflate:     stored block%s\n",
+        //        state.last ? " (last)" : ""));
+        state.mode = STORED;
+        break;
+      case 1:                             /* fixed block */
+        fixedtables(state);
+        //Tracev((stderr, "inflate:     fixed codes block%s\n",
+        //        state.last ? " (last)" : ""));
+        state.mode = LEN_;             /* decode codes */
+        if (flush === Z_TREES) {
+          //--- DROPBITS(2) ---//
+          hold >>>= 2;
+          bits -= 2;
+          //---//
+          break inf_leave;
+        }
+        break;
+      case 2:                             /* dynamic block */
+        //Tracev((stderr, "inflate:     dynamic codes block%s\n",
+        //        state.last ? " (last)" : ""));
+        state.mode = TABLE;
+        break;
+      case 3:
+        strm.msg = 'invalid block type';
+        state.mode = BAD;
+      }
+      //--- DROPBITS(2) ---//
+      hold >>>= 2;
+      bits -= 2;
+      //---//
+      break;
+    case STORED:
+      //--- BYTEBITS() ---// /* go to byte boundary */
+      hold >>>= bits & 7;
+      bits -= bits & 7;
+      //---//
+      //=== NEEDBITS(32); */
+      while (bits < 32) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
+        strm.msg = 'invalid stored block lengths';
+        state.mode = BAD;
+        break;
+      }
+      state.length = hold & 0xffff;
+      //Tracev((stderr, "inflate:       stored length %u\n",
+      //        state.length));
+      //=== INITBITS();
+      hold = 0;
+      bits = 0;
+      //===//
+      state.mode = COPY_;
+      if (flush === Z_TREES) { break inf_leave; }
+      /* falls through */
+    case COPY_:
+      state.mode = COPY;
+      /* falls through */
+    case COPY:
+      copy = state.length;
+      if (copy) {
+        if (copy > have) { copy = have; }
+        if (copy > left) { copy = left; }
+        if (copy === 0) { break inf_leave; }
+        //--- zmemcpy(put, next, copy); ---
+        utils.arraySet(output, input, next, copy, put);
+        //---//
+        have -= copy;
+        next += copy;
+        left -= copy;
+        put += copy;
+        state.length -= copy;
+        break;
+      }
+      //Tracev((stderr, "inflate:       stored end\n"));
+      state.mode = TYPE;
+      break;
+    case TABLE:
+      //=== NEEDBITS(14); */
+      while (bits < 14) {
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+      }
+      //===//
+      state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
+      //--- DROPBITS(5) ---//
+      hold >>>= 5;
+      bits -= 5;
+      //---//
+      state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
+      //--- DROPBITS(5) ---//
+      hold >>>= 5;
+      bits -= 5;
+      //---//
+      state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
+      //--- DROPBITS(4) ---//
+      hold >>>= 4;
+      bits -= 4;
+      //---//
+//#ifndef PKZIP_BUG_WORKAROUND
+      if (state.nlen > 286 || state.ndist > 30) {
+        strm.msg = 'too many length or distance symbols';
+        state.mode = BAD;
+        break;
+      }
+//#endif
+      //Tracev((stderr, "inflate:       table sizes ok\n"));
+      state.have = 0;
+      state.mode = LENLENS;
+      /* falls through */
+    case LENLENS:
+      while (state.have < state.ncode) {
+        //=== NEEDBITS(3);
+        while (bits < 3) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
+        //--- DROPBITS(3) ---//
+        hold >>>= 3;
+        bits -= 3;
+        //---//
+      }
+      while (state.have < 19) {
+        state.lens[order[state.have++]] = 0;
+      }
+      // We have separate tables & no pointers. 2 commented lines below not needed.
+      //state.next = state.codes;
+      //state.lencode = state.next;
+      // Switch to use dynamic table
+      state.lencode = state.lendyn;
+      state.lenbits = 7;
+
+      opts = { bits: state.lenbits };
+      ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
+      state.lenbits = opts.bits;
+
+      if (ret) {
+        strm.msg = 'invalid code lengths set';
+        state.mode = BAD;
+        break;
+      }
+      //Tracev((stderr, "inflate:       code lengths ok\n"));
+      state.have = 0;
+      state.mode = CODELENS;
+      /* falls through */
+    case CODELENS:
+      while (state.have < state.nlen + state.ndist) {
+        for (;;) {
+          here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
+          here_bits = here >>> 24;
+          here_op = (here >>> 16) & 0xff;
+          here_val = here & 0xffff;
+
+          if ((here_bits) <= bits) { break; }
+          //--- PULLBYTE() ---//
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+          //---//
+        }
+        if (here_val < 16) {
+          //--- DROPBITS(here.bits) ---//
+          hold >>>= here_bits;
+          bits -= here_bits;
+          //---//
+          state.lens[state.have++] = here_val;
+        }
+        else {
+          if (here_val === 16) {
+            //=== NEEDBITS(here.bits + 2);
+            n = here_bits + 2;
+            while (bits < n) {
+              if (have === 0) { break inf_leave; }
+              have--;
+              hold += input[next++] << bits;
+              bits += 8;
+            }
+            //===//
+            //--- DROPBITS(here.bits) ---//
+            hold >>>= here_bits;
+            bits -= here_bits;
+            //---//
+            if (state.have === 0) {
+              strm.msg = 'invalid bit length repeat';
+              state.mode = BAD;
+              break;
+            }
+            len = state.lens[state.have - 1];
+            copy = 3 + (hold & 0x03);//BITS(2);
+            //--- DROPBITS(2) ---//
+            hold >>>= 2;
+            bits -= 2;
+            //---//
+          }
+          else if (here_val === 17) {
+            //=== NEEDBITS(here.bits + 3);
+            n = here_bits + 3;
+            while (bits < n) {
+              if (have === 0) { break inf_leave; }
+              have--;
+              hold += input[next++] << bits;
+              bits += 8;
+            }
+            //===//
+            //--- DROPBITS(here.bits) ---//
+            hold >>>= here_bits;
+            bits -= here_bits;
+            //---//
+            len = 0;
+            copy = 3 + (hold & 0x07);//BITS(3);
+            //--- DROPBITS(3) ---//
+            hold >>>= 3;
+            bits -= 3;
+            //---//
+          }
+          else {
+            //=== NEEDBITS(here.bits + 7);
+            n = here_bits + 7;
+            while (bits < n) {
+              if (have === 0) { break inf_leave; }
+              have--;
+              hold += input[next++] << bits;
+              bits += 8;
+            }
+            //===//
+            //--- DROPBITS(here.bits) ---//
+            hold >>>= here_bits;
+            bits -= here_bits;
+            //---//
+            len = 0;
+            copy = 11 + (hold & 0x7f);//BITS(7);
+            //--- DROPBITS(7) ---//
+            hold >>>= 7;
+            bits -= 7;
+            //---//
+          }
+          if (state.have + copy > state.nlen + state.ndist) {
+            strm.msg = 'invalid bit length repeat';
+            state.mode = BAD;
+            break;
+          }
+          while (copy--) {
+            state.lens[state.have++] = len;
+          }
+        }
+      }
+
+      /* handle error breaks in while */
+      if (state.mode === BAD) { break; }
+
+      /* check for end-of-block code (better have one) */
+      if (state.lens[256] === 0) {
+        strm.msg = 'invalid code -- missing end-of-block';
+        state.mode = BAD;
+        break;
+      }
+
+      /* build code tables -- note: do not change the lenbits or distbits
+         values here (9 and 6) without reading the comments in inftrees.h
+         concerning the ENOUGH constants, which depend on those values */
+      state.lenbits = 9;
+
+      opts = { bits: state.lenbits };
+      ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
+      // We have separate tables & no pointers. 2 commented lines below not needed.
+      // state.next_index = opts.table_index;
+      state.lenbits = opts.bits;
+      // state.lencode = state.next;
+
+      if (ret) {
+        strm.msg = 'invalid literal/lengths set';
+        state.mode = BAD;
+        break;
+      }
+
+      state.distbits = 6;
+      //state.distcode.copy(state.codes);
+      // Switch to use dynamic table
+      state.distcode = state.distdyn;
+      opts = { bits: state.distbits };
+      ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
+      // We have separate tables & no pointers. 2 commented lines below not needed.
+      // state.next_index = opts.table_index;
+      state.distbits = opts.bits;
+      // state.distcode = state.next;
+
+      if (ret) {
+        strm.msg = 'invalid distances set';
+        state.mode = BAD;
+        break;
+      }
+      //Tracev((stderr, 'inflate:       codes ok\n'));
+      state.mode = LEN_;
+      if (flush === Z_TREES) { break inf_leave; }
+      /* falls through */
+    case LEN_:
+      state.mode = LEN;
+      /* falls through */
+    case LEN:
+      if (have >= 6 && left >= 258) {
+        //--- RESTORE() ---
+        strm.next_out = put;
+        strm.avail_out = left;
+        strm.next_in = next;
+        strm.avail_in = have;
+        state.hold = hold;
+        state.bits = bits;
+        //---
+        inflate_fast(strm, _out);
+        //--- LOAD() ---
+        put = strm.next_out;
+        output = strm.output;
+        left = strm.avail_out;
+        next = strm.next_in;
+        input = strm.input;
+        have = strm.avail_in;
+        hold = state.hold;
+        bits = state.bits;
+        //---
+
+        if (state.mode === TYPE) {
+          state.back = -1;
+        }
+        break;
+      }
+      state.back = 0;
+      for (;;) {
+        here = state.lencode[hold & ((1 << state.lenbits) - 1)];  /*BITS(state.lenbits)*/
+        here_bits = here >>> 24;
+        here_op = (here >>> 16) & 0xff;
+        here_val = here & 0xffff;
+
+        if (here_bits <= bits) { break; }
+        //--- PULLBYTE() ---//
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+        //---//
+      }
+      if (here_op && (here_op & 0xf0) === 0) {
+        last_bits = here_bits;
+        last_op = here_op;
+        last_val = here_val;
+        for (;;) {
+          here = state.lencode[last_val +
+                  ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
+          here_bits = here >>> 24;
+          here_op = (here >>> 16) & 0xff;
+          here_val = here & 0xffff;
+
+          if ((last_bits + here_bits) <= bits) { break; }
+          //--- PULLBYTE() ---//
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+          //---//
+        }
+        //--- DROPBITS(last.bits) ---//
+        hold >>>= last_bits;
+        bits -= last_bits;
+        //---//
+        state.back += last_bits;
+      }
+      //--- DROPBITS(here.bits) ---//
+      hold >>>= here_bits;
+      bits -= here_bits;
+      //---//
+      state.back += here_bits;
+      state.length = here_val;
+      if (here_op === 0) {
+        //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+        //        "inflate:         literal '%c'\n" :
+        //        "inflate:         literal 0x%02x\n", here.val));
+        state.mode = LIT;
+        break;
+      }
+      if (here_op & 32) {
+        //Tracevv((stderr, "inflate:         end of block\n"));
+        state.back = -1;
+        state.mode = TYPE;
+        break;
+      }
+      if (here_op & 64) {
+        strm.msg = 'invalid literal/length code';
+        state.mode = BAD;
+        break;
+      }
+      state.extra = here_op & 15;
+      state.mode = LENEXT;
+      /* falls through */
+    case LENEXT:
+      if (state.extra) {
+        //=== NEEDBITS(state.extra);
+        n = state.extra;
+        while (bits < n) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
+        //--- DROPBITS(state.extra) ---//
+        hold >>>= state.extra;
+        bits -= state.extra;
+        //---//
+        state.back += state.extra;
+      }
+      //Tracevv((stderr, "inflate:         length %u\n", state.length));
+      state.was = state.length;
+      state.mode = DIST;
+      /* falls through */
+    case DIST:
+      for (;;) {
+        here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
+        here_bits = here >>> 24;
+        here_op = (here >>> 16) & 0xff;
+        here_val = here & 0xffff;
+
+        if ((here_bits) <= bits) { break; }
+        //--- PULLBYTE() ---//
+        if (have === 0) { break inf_leave; }
+        have--;
+        hold += input[next++] << bits;
+        bits += 8;
+        //---//
+      }
+      if ((here_op & 0xf0) === 0) {
+        last_bits = here_bits;
+        last_op = here_op;
+        last_val = here_val;
+        for (;;) {
+          here = state.distcode[last_val +
+                  ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
+          here_bits = here >>> 24;
+          here_op = (here >>> 16) & 0xff;
+          here_val = here & 0xffff;
+
+          if ((last_bits + here_bits) <= bits) { break; }
+          //--- PULLBYTE() ---//
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+          //---//
+        }
+        //--- DROPBITS(last.bits) ---//
+        hold >>>= last_bits;
+        bits -= last_bits;
+        //---//
+        state.back += last_bits;
+      }
+      //--- DROPBITS(here.bits) ---//
+      hold >>>= here_bits;
+      bits -= here_bits;
+      //---//
+      state.back += here_bits;
+      if (here_op & 64) {
+        strm.msg = 'invalid distance code';
+        state.mode = BAD;
+        break;
+      }
+      state.offset = here_val;
+      state.extra = (here_op) & 15;
+      state.mode = DISTEXT;
+      /* falls through */
+    case DISTEXT:
+      if (state.extra) {
+        //=== NEEDBITS(state.extra);
+        n = state.extra;
+        while (bits < n) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
+        //--- DROPBITS(state.extra) ---//
+        hold >>>= state.extra;
+        bits -= state.extra;
+        //---//
+        state.back += state.extra;
+      }
+//#ifdef INFLATE_STRICT
+      if (state.offset > state.dmax) {
+        strm.msg = 'invalid distance too far back';
+        state.mode = BAD;
+        break;
+      }
+//#endif
+      //Tracevv((stderr, "inflate:         distance %u\n", state.offset));
+      state.mode = MATCH;
+      /* falls through */
+    case MATCH:
+      if (left === 0) { break inf_leave; }
+      copy = _out - left;
+      if (state.offset > copy) {         /* copy from window */
+        copy = state.offset - copy;
+        if (copy > state.whave) {
+          if (state.sane) {
+            strm.msg = 'invalid distance too far back';
+            state.mode = BAD;
+            break;
+          }
+// (!) This block is disabled in zlib defailts,
+// don't enable it for binary compatibility
+//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+//          Trace((stderr, "inflate.c too far\n"));
+//          copy -= state.whave;
+//          if (copy > state.length) { copy = state.length; }
+//          if (copy > left) { copy = left; }
+//          left -= copy;
+//          state.length -= copy;
+//          do {
+//            output[put++] = 0;
+//          } while (--copy);
+//          if (state.length === 0) { state.mode = LEN; }
+//          break;
+//#endif
+        }
+        if (copy > state.wnext) {
+          copy -= state.wnext;
+          from = state.wsize - copy;
+        }
+        else {
+          from = state.wnext - copy;
+        }
+        if (copy > state.length) { copy = state.length; }
+        from_source = state.window;
+      }
+      else {                              /* copy from output */
+        from_source = output;
+        from = put - state.offset;
+        copy = state.length;
+      }
+      if (copy > left) { copy = left; }
+      left -= copy;
+      state.length -= copy;
+      do {
+        output[put++] = from_source[from++];
+      } while (--copy);
+      if (state.length === 0) { state.mode = LEN; }
+      break;
+    case LIT:
+      if (left === 0) { break inf_leave; }
+      output[put++] = state.length;
+      left--;
+      state.mode = LEN;
+      break;
+    case CHECK:
+      if (state.wrap) {
+        //=== NEEDBITS(32);
+        while (bits < 32) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          // Use '|' insdead of '+' to make sure that result is signed
+          hold |= input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        _out -= left;
+        strm.total_out += _out;
+        state.total += _out;
+        if (_out) {
+          strm.adler = state.check =
+              /*UPDATE(state.check, put - _out, _out);*/
+              (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
+
+        }
+        _out = left;
+        // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
+        if ((state.flags ? hold : zswap32(hold)) !== state.check) {
+          strm.msg = 'incorrect data check';
+          state.mode = BAD;
+          break;
+        }
+        //=== INITBITS();
+        hold = 0;
+        bits = 0;
+        //===//
+        //Tracev((stderr, "inflate:   check matches trailer\n"));
+      }
+      state.mode = LENGTH;
+      /* falls through */
+    case LENGTH:
+      if (state.wrap && state.flags) {
+        //=== NEEDBITS(32);
+        while (bits < 32) {
+          if (have === 0) { break inf_leave; }
+          have--;
+          hold += input[next++] << bits;
+          bits += 8;
+        }
+        //===//
+        if (hold !== (state.total & 0xffffffff)) {
+          strm.msg = 'incorrect length check';
+          state.mode = BAD;
+          break;
+        }
+        //=== INITBITS();
+        hold = 0;
+        bits = 0;
+        //===//
+        //Tracev((stderr, "inflate:   length matches trailer\n"));
+      }
+      state.mode = DONE;
+      /* falls through */
+    case DONE:
+      ret = Z_STREAM_END;
+      break inf_leave;
+    case BAD:
+      ret = Z_DATA_ERROR;
+      break inf_leave;
+    case MEM:
+      return Z_MEM_ERROR;
+    case SYNC:
+      /* falls through */
+    default:
+      return Z_STREAM_ERROR;
+    }
+  }
+
+  // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
+
+  /*
+     Return from inflate(), updating the total counts and the check value.
+     If there was no progress during the inflate() call, return a buffer
+     error.  Call updatewindow() to create and/or update the window state.
+     Note: a memory error from inflate() is non-recoverable.
+   */
+
+  //--- RESTORE() ---
+  strm.next_out = put;
+  strm.avail_out = left;
+  strm.next_in = next;
+  strm.avail_in = have;
+  state.hold = hold;
+  state.bits = bits;
+  //---
+
+  if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
+                      (state.mode < CHECK || flush !== Z_FINISH))) {
+    if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
+      state.mode = MEM;
+      return Z_MEM_ERROR;
+    }
+  }
+  _in -= strm.avail_in;
+  _out -= strm.avail_out;
+  strm.total_in += _in;
+  strm.total_out += _out;
+  state.total += _out;
+  if (state.wrap && _out) {
+    strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
+      (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
+  }
+  strm.data_type = state.bits + (state.last ? 64 : 0) +
+                    (state.mode === TYPE ? 128 : 0) +
+                    (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
+  if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
+    ret = Z_BUF_ERROR;
+  }
+  return ret;
+}
+
+function inflateEnd(strm) {
+
+  if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
+    return Z_STREAM_ERROR;
+  }
+
+  var state = strm.state;
+  if (state.window) {
+    state.window = null;
+  }
+  strm.state = null;
+  return Z_OK;
+}
+
+function inflateGetHeader(strm, head) {
+  var state;
+
+  /* check state */
+  if (!strm || !strm.state) { return Z_STREAM_ERROR; }
+  state = strm.state;
+  if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
+
+  /* save header structure */
+  state.head = head;
+  head.done = false;
+  return Z_OK;
+}
+
+function inflateSetDictionary(strm, dictionary) {
+  var dictLength = dictionary.length;
+
+  var state;
+  var dictid;
+  var ret;
+
+  /* check state */
+  if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }
+  state = strm.state;
+
+  if (state.wrap !== 0 && state.mode !== DICT) {
+    return Z_STREAM_ERROR;
+  }
+
+  /* check for correct dictionary identifier */
+  if (state.mode === DICT) {
+    dictid = 1; /* adler32(0, null, 0)*/
+    /* dictid = adler32(dictid, dictionary, dictLength); */
+    dictid = adler32(dictid, dictionary, dictLength, 0);
+    if (dictid !== state.check) {
+      return Z_DATA_ERROR;
+    }
+  }
+  /* copy dictionary to window using updatewindow(), which will amend the
+   existing dictionary if appropriate */
+  ret = updatewindow(strm, dictionary, dictLength, dictLength);
+  if (ret) {
+    state.mode = MEM;
+    return Z_MEM_ERROR;
+  }
+  state.havedict = 1;
+  // Tracev((stderr, "inflate:   dictionary set\n"));
+  return Z_OK;
+}
+
+exports.inflateReset = inflateReset;
+exports.inflateReset2 = inflateReset2;
+exports.inflateResetKeep = inflateResetKeep;
+exports.inflateInit = inflateInit;
+exports.inflateInit2 = inflateInit2;
+exports.inflate = inflate;
+exports.inflateEnd = inflateEnd;
+exports.inflateGetHeader = inflateGetHeader;
+exports.inflateSetDictionary = inflateSetDictionary;
+exports.inflateInfo = 'pako inflate (from Nodeca project)';
+
+/* Not implemented
+exports.inflateCopy = inflateCopy;
+exports.inflateGetDictionary = inflateGetDictionary;
+exports.inflateMark = inflateMark;
+exports.inflatePrime = inflatePrime;
+exports.inflateSync = inflateSync;
+exports.inflateSyncPoint = inflateSyncPoint;
+exports.inflateUndermine = inflateUndermine;
+*/
+
+},{"../utils/common":41,"./adler32":43,"./crc32":45,"./inffast":48,"./inftrees":50}],50:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+var utils = require('../utils/common');
+
+var MAXBITS = 15;
+var ENOUGH_LENS = 852;
+var ENOUGH_DISTS = 592;
+//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
+
+var CODES = 0;
+var LENS = 1;
+var DISTS = 2;
+
+var lbase = [ /* Length codes 257..285 base */
+  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+];
+
+var lext = [ /* Length codes 257..285 extra */
+  16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+  19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
+];
+
+var dbase = [ /* Distance codes 0..29 base */
+  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+  8193, 12289, 16385, 24577, 0, 0
+];
+
+var dext = [ /* Distance codes 0..29 extra */
+  16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+  23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+  28, 28, 29, 29, 64, 64
+];
+
+module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
+{
+  var bits = opts.bits;
+      //here = opts.here; /* table entry for duplication */
+
+  var len = 0;               /* a code's length in bits */
+  var sym = 0;               /* index of code symbols */
+  var min = 0, max = 0;          /* minimum and maximum code lengths */
+  var root = 0;              /* number of index bits for root table */
+  var curr = 0;              /* number of index bits for current table */
+  var drop = 0;              /* code bits to drop for sub-table */
+  var left = 0;                   /* number of prefix codes available */
+  var used = 0;              /* code entries in table used */
+  var huff = 0;              /* Huffman code */
+  var incr;              /* for incrementing code, index */
+  var fill;              /* index for replicating entries */
+  var low;               /* low bits for current root entry */
+  var mask;              /* mask for low root bits */
+  var next;             /* next available space in table */
+  var base = null;     /* base value table to use */
+  var base_index = 0;
+//  var shoextra;    /* extra bits table to use */
+  var end;                    /* use base and extra for symbol > end */
+  var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];    /* number of codes of each length */
+  var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1];     /* offsets in table for each length */
+  var extra = null;
+  var extra_index = 0;
+
+  var here_bits, here_op, here_val;
+
+  /*
+   Process a set of code lengths to create a canonical Huffman code.  The
+   code lengths are lens[0..codes-1].  Each length corresponds to the
+   symbols 0..codes-1.  The Huffman code is generated by first sorting the
+   symbols by length from short to long, and retaining the symbol order
+   for codes with equal lengths.  Then the code starts with all zero bits
+   for the first code of the shortest length, and the codes are integer
+   increments for the same length, and zeros are appended as the length
+   increases.  For the deflate format, these bits are stored backwards
+   from their more natural integer increment ordering, and so when the
+   decoding tables are built in the large loop below, the integer codes
+   are incremented backwards.
+
+   This routine assumes, but does not check, that all of the entries in
+   lens[] are in the range 0..MAXBITS.  The caller must assure this.
+   1..MAXBITS is interpreted as that code length.  zero means that that
+   symbol does not occur in this code.
+
+   The codes are sorted by computing a count of codes for each length,
+   creating from that a table of starting indices for each length in the
+   sorted table, and then entering the symbols in order in the sorted
+   table.  The sorted table is work[], with that space being provided by
+   the caller.
+
+   The length counts are used for other purposes as well, i.e. finding
+   the minimum and maximum length codes, determining if there are any
+   codes at all, checking for a valid set of lengths, and looking ahead
+   at length counts to determine sub-table sizes when building the
+   decoding tables.
+   */
+
+  /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+  for (len = 0; len <= MAXBITS; len++) {
+    count[len] = 0;
+  }
+  for (sym = 0; sym < codes; sym++) {
+    count[lens[lens_index + sym]]++;
+  }
+
+  /* bound code lengths, force root to be within code lengths */
+  root = bits;
+  for (max = MAXBITS; max >= 1; max--) {
+    if (count[max] !== 0) { break; }
+  }
+  if (root > max) {
+    root = max;
+  }
+  if (max === 0) {                     /* no symbols to code at all */
+    //table.op[opts.table_index] = 64;  //here.op = (var char)64;    /* invalid code marker */
+    //table.bits[opts.table_index] = 1;   //here.bits = (var char)1;
+    //table.val[opts.table_index++] = 0;   //here.val = (var short)0;
+    table[table_index++] = (1 << 24) | (64 << 16) | 0;
+
+
+    //table.op[opts.table_index] = 64;
+    //table.bits[opts.table_index] = 1;
+    //table.val[opts.table_index++] = 0;
+    table[table_index++] = (1 << 24) | (64 << 16) | 0;
+
+    opts.bits = 1;
+    return 0;     /* no symbols, but wait for decoding to report error */
+  }
+  for (min = 1; min < max; min++) {
+    if (count[min] !== 0) { break; }
+  }
+  if (root < min) {
+    root = min;
+  }
+
+  /* check for an over-subscribed or incomplete set of lengths */
+  left = 1;
+  for (len = 1; len <= MAXBITS; len++) {
+    left <<= 1;
+    left -= count[len];
+    if (left < 0) {
+      return -1;
+    }        /* over-subscribed */
+  }
+  if (left > 0 && (type === CODES || max !== 1)) {
+    return -1;                      /* incomplete set */
+  }
+
+  /* generate offsets into symbol table for each length for sorting */
+  offs[1] = 0;
+  for (len = 1; len < MAXBITS; len++) {
+    offs[len + 1] = offs[len] + count[len];
+  }
+
+  /* sort symbols by length, by symbol order within each length */
+  for (sym = 0; sym < codes; sym++) {
+    if (lens[lens_index + sym] !== 0) {
+      work[offs[lens[lens_index + sym]]++] = sym;
+    }
+  }
+
+  /*
+   Create and fill in decoding tables.  In this loop, the table being
+   filled is at next and has curr index bits.  The code being used is huff
+   with length len.  That code is converted to an index by dropping drop
+   bits off of the bottom.  For codes where len is less than drop + curr,
+   those top drop + curr - len bits are incremented through all values to
+   fill the table with replicated entries.
+
+   root is the number of index bits for the root table.  When len exceeds
+   root, sub-tables are created pointed to by the root entry with an index
+   of the low root bits of huff.  This is saved in low to check for when a
+   new sub-table should be started.  drop is zero when the root table is
+   being filled, and drop is root when sub-tables are being filled.
+
+   When a new sub-table is needed, it is necessary to look ahead in the
+   code lengths to determine what size sub-table is needed.  The length
+   counts are used for this, and so count[] is decremented as codes are
+   entered in the tables.
+
+   used keeps track of how many table entries have been allocated from the
+   provided *table space.  It is checked for LENS and DIST tables against
+   the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+   the initial root table size constants.  See the comments in inftrees.h
+   for more information.
+
+   sym increments through all symbols, and the loop terminates when
+   all codes of length max, i.e. all codes, have been processed.  This
+   routine permits incomplete codes, so another loop after this one fills
+   in the rest of the decoding tables with invalid code markers.
+   */
+
+  /* set up for code type */
+  // poor man optimization - use if-else instead of switch,
+  // to avoid deopts in old v8
+  if (type === CODES) {
+    base = extra = work;    /* dummy value--not used */
+    end = 19;
+
+  } else if (type === LENS) {
+    base = lbase;
+    base_index -= 257;
+    extra = lext;
+    extra_index -= 257;
+    end = 256;
+
+  } else {                    /* DISTS */
+    base = dbase;
+    extra = dext;
+    end = -1;
+  }
+
+  /* initialize opts for loop */
+  huff = 0;                   /* starting code */
+  sym = 0;                    /* starting code symbol */
+  len = min;                  /* starting code length */
+  next = table_index;              /* current table to fill in */
+  curr = root;                /* current table index bits */
+  drop = 0;                   /* current bits to drop from code for index */
+  low = -1;                   /* trigger new sub-table when len > root */
+  used = 1 << root;          /* use root table entries */
+  mask = used - 1;            /* mask for comparing low */
+
+  /* check available table space */
+  if ((type === LENS && used > ENOUGH_LENS) ||
+    (type === DISTS && used > ENOUGH_DISTS)) {
+    return 1;
+  }
+
+  /* process all codes and make table entries */
+  for (;;) {
+    /* create table entry */
+    here_bits = len - drop;
+    if (work[sym] < end) {
+      here_op = 0;
+      here_val = work[sym];
+    }
+    else if (work[sym] > end) {
+      here_op = extra[extra_index + work[sym]];
+      here_val = base[base_index + work[sym]];
+    }
+    else {
+      here_op = 32 + 64;         /* end of block */
+      here_val = 0;
+    }
+
+    /* replicate for those indices with low len bits equal to huff */
+    incr = 1 << (len - drop);
+    fill = 1 << curr;
+    min = fill;                 /* save offset to next table */
+    do {
+      fill -= incr;
+      table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
+    } while (fill !== 0);
+
+    /* backwards increment the len-bit code huff */
+    incr = 1 << (len - 1);
+    while (huff & incr) {
+      incr >>= 1;
+    }
+    if (incr !== 0) {
+      huff &= incr - 1;
+      huff += incr;
+    } else {
+      huff = 0;
+    }
+
+    /* go to next symbol, update count, len */
+    sym++;
+    if (--count[len] === 0) {
+      if (len === max) { break; }
+      len = lens[lens_index + work[sym]];
+    }
+
+    /* create new sub-table if needed */
+    if (len > root && (huff & mask) !== low) {
+      /* if first time, transition to sub-tables */
+      if (drop === 0) {
+        drop = root;
+      }
+
+      /* increment past last table */
+      next += min;            /* here min is 1 << curr */
+
+      /* determine length of next table */
+      curr = len - drop;
+      left = 1 << curr;
+      while (curr + drop < max) {
+        left -= count[curr + drop];
+        if (left <= 0) { break; }
+        curr++;
+        left <<= 1;
+      }
+
+      /* check for enough space */
+      used += 1 << curr;
+      if ((type === LENS && used > ENOUGH_LENS) ||
+        (type === DISTS && used > ENOUGH_DISTS)) {
+        return 1;
+      }
+
+      /* point entry in root table to sub-table */
+      low = huff & mask;
+      /*table.op[low] = curr;
+      table.bits[low] = root;
+      table.val[low] = next - opts.table_index;*/
+      table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
+    }
+  }
+
+  /* fill in remaining table entry if code is incomplete (guaranteed to have
+   at most one remaining entry, since if the code is incomplete, the
+   maximum code length that was allowed to get this far is one bit) */
+  if (huff !== 0) {
+    //table.op[next + huff] = 64;            /* invalid code marker */
+    //table.bits[next + huff] = len - drop;
+    //table.val[next + huff] = 0;
+    table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
+  }
+
+  /* set return parameters */
+  //opts.table_index += used;
+  opts.bits = root;
+  return 0;
+};
+
+},{"../utils/common":41}],51:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+module.exports = {
+  2:      'need dictionary',     /* Z_NEED_DICT       2  */
+  1:      'stream end',          /* Z_STREAM_END      1  */
+  0:      '',                    /* Z_OK              0  */
+  '-1':   'file error',          /* Z_ERRNO         (-1) */
+  '-2':   'stream error',        /* Z_STREAM_ERROR  (-2) */
+  '-3':   'data error',          /* Z_DATA_ERROR    (-3) */
+  '-4':   'insufficient memory', /* Z_MEM_ERROR     (-4) */
+  '-5':   'buffer error',        /* Z_BUF_ERROR     (-5) */
+  '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
+};
+
+},{}],52:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+var utils = require('../utils/common');
+
+/* Public constants ==========================================================*/
+/* ===========================================================================*/
+
+
+//var Z_FILTERED          = 1;
+//var Z_HUFFMAN_ONLY      = 2;
+//var Z_RLE               = 3;
+var Z_FIXED               = 4;
+//var Z_DEFAULT_STRATEGY  = 0;
+
+/* Possible values of the data_type field (though see inflate()) */
+var Z_BINARY              = 0;
+var Z_TEXT                = 1;
+//var Z_ASCII             = 1; // = Z_TEXT
+var Z_UNKNOWN             = 2;
+
+/*============================================================================*/
+
+
+function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
+
+// From zutil.h
+
+var STORED_BLOCK = 0;
+var STATIC_TREES = 1;
+var DYN_TREES    = 2;
+/* The three kinds of block type */
+
+var MIN_MATCH    = 3;
+var MAX_MATCH    = 258;
+/* The minimum and maximum match lengths */
+
+// From deflate.h
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+var LENGTH_CODES  = 29;
+/* number of length codes, not counting the special END_BLOCK code */
+
+var LITERALS      = 256;
+/* number of literal bytes 0..255 */
+
+var L_CODES       = LITERALS + 1 + LENGTH_CODES;
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+var D_CODES       = 30;
+/* number of distance codes */
+
+var BL_CODES      = 19;
+/* number of codes used to transfer the bit lengths */
+
+var HEAP_SIZE     = 2 * L_CODES + 1;
+/* maximum heap size */
+
+var MAX_BITS      = 15;
+/* All codes must not exceed MAX_BITS bits */
+
+var Buf_size      = 16;
+/* size of bit buffer in bi_buf */
+
+
+/* ===========================================================================
+ * Constants
+ */
+
+var MAX_BL_BITS = 7;
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+var END_BLOCK   = 256;
+/* end of block literal code */
+
+var REP_3_6     = 16;
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+var REPZ_3_10   = 17;
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+var REPZ_11_138 = 18;
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+/* eslint-disable comma-spacing,array-bracket-spacing */
+var extra_lbits =   /* extra bits for each length code */
+  [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
+
+var extra_dbits =   /* extra bits for each distance code */
+  [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
+
+var extra_blbits =  /* extra bits for each bit length code */
+  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
+
+var bl_order =
+  [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
+/* eslint-enable comma-spacing,array-bracket-spacing */
+
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+// We pre-fill arrays with 0 to avoid uninitialized gaps
+
+var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
+
+// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1
+var static_ltree  = new Array((L_CODES + 2) * 2);
+zero(static_ltree);
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+var static_dtree  = new Array(D_CODES * 2);
+zero(static_dtree);
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+var _dist_code    = new Array(DIST_CODE_LEN);
+zero(_dist_code);
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+var _length_code  = new Array(MAX_MATCH - MIN_MATCH + 1);
+zero(_length_code);
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+var base_length   = new Array(LENGTH_CODES);
+zero(base_length);
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+var base_dist     = new Array(D_CODES);
+zero(base_dist);
+/* First normalized distance for each code (0 = distance of 1) */
+
+
+function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
+
+  this.static_tree  = static_tree;  /* static tree or NULL */
+  this.extra_bits   = extra_bits;   /* extra bits for each code or NULL */
+  this.extra_base   = extra_base;   /* base index for extra_bits */
+  this.elems        = elems;        /* max number of elements in the tree */
+  this.max_length   = max_length;   /* max bit length for the codes */
+
+  // show if `static_tree` has data or dummy - needed for monomorphic objects
+  this.has_stree    = static_tree && static_tree.length;
+}
+
+
+var static_l_desc;
+var static_d_desc;
+var static_bl_desc;
+
+
+function TreeDesc(dyn_tree, stat_desc) {
+  this.dyn_tree = dyn_tree;     /* the dynamic tree */
+  this.max_code = 0;            /* largest code with non zero frequency */
+  this.stat_desc = stat_desc;   /* the corresponding static tree */
+}
+
+
+
+function d_code(dist) {
+  return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
+}
+
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+function put_short(s, w) {
+//    put_byte(s, (uch)((w) & 0xff));
+//    put_byte(s, (uch)((ush)(w) >> 8));
+  s.pending_buf[s.pending++] = (w) & 0xff;
+  s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
+}
+
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+function send_bits(s, value, length) {
+  if (s.bi_valid > (Buf_size - length)) {
+    s.bi_buf |= (value << s.bi_valid) & 0xffff;
+    put_short(s, s.bi_buf);
+    s.bi_buf = value >> (Buf_size - s.bi_valid);
+    s.bi_valid += length - Buf_size;
+  } else {
+    s.bi_buf |= (value << s.bi_valid) & 0xffff;
+    s.bi_valid += length;
+  }
+}
+
+
+function send_code(s, c, tree) {
+  send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
+}
+
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+function bi_reverse(code, len) {
+  var res = 0;
+  do {
+    res |= code & 1;
+    code >>>= 1;
+    res <<= 1;
+  } while (--len > 0);
+  return res >>> 1;
+}
+
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+function bi_flush(s) {
+  if (s.bi_valid === 16) {
+    put_short(s, s.bi_buf);
+    s.bi_buf = 0;
+    s.bi_valid = 0;
+
+  } else if (s.bi_valid >= 8) {
+    s.pending_buf[s.pending++] = s.bi_buf & 0xff;
+    s.bi_buf >>= 8;
+    s.bi_valid -= 8;
+  }
+}
+
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+function gen_bitlen(s, desc)
+//    deflate_state *s;
+//    tree_desc *desc;    /* the tree descriptor */
+{
+  var tree            = desc.dyn_tree;
+  var max_code        = desc.max_code;
+  var stree           = desc.stat_desc.static_tree;
+  var has_stree       = desc.stat_desc.has_stree;
+  var extra           = desc.stat_desc.extra_bits;
+  var base            = desc.stat_desc.extra_base;
+  var max_length      = desc.stat_desc.max_length;
+  var h;              /* heap index */
+  var n, m;           /* iterate over the tree elements */
+  var bits;           /* bit length */
+  var xbits;          /* extra bits */
+  var f;              /* frequency */
+  var overflow = 0;   /* number of elements with bit length too large */
+
+  for (bits = 0; bits <= MAX_BITS; bits++) {
+    s.bl_count[bits] = 0;
+  }
+
+  /* In a first pass, compute the optimal bit lengths (which may
+   * overflow in the case of the bit length tree).
+   */
+  tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
+
+  for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
+    n = s.heap[h];
+    bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
+    if (bits > max_length) {
+      bits = max_length;
+      overflow++;
+    }
+    tree[n * 2 + 1]/*.Len*/ = bits;
+    /* We overwrite tree[n].Dad which is no longer needed */
+
+    if (n > max_code) { continue; } /* not a leaf node */
+
+    s.bl_count[bits]++;
+    xbits = 0;
+    if (n >= base) {
+      xbits = extra[n - base];
+    }
+    f = tree[n * 2]/*.Freq*/;
+    s.opt_len += f * (bits + xbits);
+    if (has_stree) {
+      s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
+    }
+  }
+  if (overflow === 0) { return; }
+
+  // Trace((stderr,"\nbit length overflow\n"));
+  /* This happens for example on obj2 and pic of the Calgary corpus */
+
+  /* Find the first bit length which could increase: */
+  do {
+    bits = max_length - 1;
+    while (s.bl_count[bits] === 0) { bits--; }
+    s.bl_count[bits]--;      /* move one leaf down the tree */
+    s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
+    s.bl_count[max_length]--;
+    /* The brother of the overflow item also moves one step up,
+     * but this does not affect bl_count[max_length]
+     */
+    overflow -= 2;
+  } while (overflow > 0);
+
+  /* Now recompute all bit lengths, scanning in increasing frequency.
+   * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+   * lengths instead of fixing only the wrong ones. This idea is taken
+   * from 'ar' written by Haruhiko Okumura.)
+   */
+  for (bits = max_length; bits !== 0; bits--) {
+    n = s.bl_count[bits];
+    while (n !== 0) {
+      m = s.heap[--h];
+      if (m > max_code) { continue; }
+      if (tree[m * 2 + 1]/*.Len*/ !== bits) {
+        // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+        s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
+        tree[m * 2 + 1]/*.Len*/ = bits;
+      }
+      n--;
+    }
+  }
+}
+
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+function gen_codes(tree, max_code, bl_count)
+//    ct_data *tree;             /* the tree to decorate */
+//    int max_code;              /* largest code with non zero frequency */
+//    ushf *bl_count;            /* number of codes at each bit length */
+{
+  var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */
+  var code = 0;              /* running code value */
+  var bits;                  /* bit index */
+  var n;                     /* code index */
+
+  /* The distribution counts are first used to generate the code values
+   * without bit reversal.
+   */
+  for (bits = 1; bits <= MAX_BITS; bits++) {
+    next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
+  }
+  /* Check that the bit counts in bl_count are consistent. The last code
+   * must be all ones.
+   */
+  //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+  //        "inconsistent bit counts");
+  //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+  for (n = 0;  n <= max_code; n++) {
+    var len = tree[n * 2 + 1]/*.Len*/;
+    if (len === 0) { continue; }
+    /* Now reverse the bits */
+    tree[n * 2]/*.Code*/ = bi_reverse(next_code[len]++, len);
+
+    //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+    //     n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+  }
+}
+
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+function tr_static_init() {
+  var n;        /* iterates over tree elements */
+  var bits;     /* bit counter */
+  var length;   /* length value */
+  var code;     /* code value */
+  var dist;     /* distance index */
+  var bl_count = new Array(MAX_BITS + 1);
+  /* number of codes at each bit length for an optimal tree */
+
+  // do check in _tr_init()
+  //if (static_init_done) return;
+
+  /* For some embedded targets, global variables are not initialized: */
+/*#ifdef NO_INIT_GLOBAL_POINTERS
+  static_l_desc.static_tree = static_ltree;
+  static_l_desc.extra_bits = extra_lbits;
+  static_d_desc.static_tree = static_dtree;
+  static_d_desc.extra_bits = extra_dbits;
+  static_bl_desc.extra_bits = extra_blbits;
+#endif*/
+
+  /* Initialize the mapping length (0..255) -> length code (0..28) */
+  length = 0;
+  for (code = 0; code < LENGTH_CODES - 1; code++) {
+    base_length[code] = length;
+    for (n = 0; n < (1 << extra_lbits[code]); n++) {
+      _length_code[length++] = code;
+    }
+  }
+  //Assert (length == 256, "tr_static_init: length != 256");
+  /* Note that the length 255 (match length 258) can be represented
+   * in two different ways: code 284 + 5 bits or code 285, so we
+   * overwrite length_code[255] to use the best encoding:
+   */
+  _length_code[length - 1] = code;
+
+  /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+  dist = 0;
+  for (code = 0; code < 16; code++) {
+    base_dist[code] = dist;
+    for (n = 0; n < (1 << extra_dbits[code]); n++) {
+      _dist_code[dist++] = code;
+    }
+  }
+  //Assert (dist == 256, "tr_static_init: dist != 256");
+  dist >>= 7; /* from now on, all distances are divided by 128 */
+  for (; code < D_CODES; code++) {
+    base_dist[code] = dist << 7;
+    for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
+      _dist_code[256 + dist++] = code;
+    }
+  }
+  //Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+  /* Construct the codes of the static literal tree */
+  for (bits = 0; bits <= MAX_BITS; bits++) {
+    bl_count[bits] = 0;
+  }
+
+  n = 0;
+  while (n <= 143) {
+    static_ltree[n * 2 + 1]/*.Len*/ = 8;
+    n++;
+    bl_count[8]++;
+  }
+  while (n <= 255) {
+    static_ltree[n * 2 + 1]/*.Len*/ = 9;
+    n++;
+    bl_count[9]++;
+  }
+  while (n <= 279) {
+    static_ltree[n * 2 + 1]/*.Len*/ = 7;
+    n++;
+    bl_count[7]++;
+  }
+  while (n <= 287) {
+    static_ltree[n * 2 + 1]/*.Len*/ = 8;
+    n++;
+    bl_count[8]++;
+  }
+  /* Codes 286 and 287 do not exist, but we must include them in the
+   * tree construction to get a canonical Huffman tree (longest code
+   * all ones)
+   */
+  gen_codes(static_ltree, L_CODES + 1, bl_count);
+
+  /* The static distance tree is trivial: */
+  for (n = 0; n < D_CODES; n++) {
+    static_dtree[n * 2 + 1]/*.Len*/ = 5;
+    static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
+  }
+
+  // Now data ready and we can init static trees
+  static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
+  static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS);
+  static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0,         BL_CODES, MAX_BL_BITS);
+
+  //static_init_done = true;
+}
+
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+function init_block(s) {
+  var n; /* iterates over tree elements */
+
+  /* Initialize the trees. */
+  for (n = 0; n < L_CODES;  n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; }
+  for (n = 0; n < D_CODES;  n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; }
+  for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; }
+
+  s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
+  s.opt_len = s.static_len = 0;
+  s.last_lit = s.matches = 0;
+}
+
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+function bi_windup(s)
+{
+  if (s.bi_valid > 8) {
+    put_short(s, s.bi_buf);
+  } else if (s.bi_valid > 0) {
+    //put_byte(s, (Byte)s->bi_buf);
+    s.pending_buf[s.pending++] = s.bi_buf;
+  }
+  s.bi_buf = 0;
+  s.bi_valid = 0;
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+function copy_block(s, buf, len, header)
+//DeflateState *s;
+//charf    *buf;    /* the input data */
+//unsigned len;     /* its length */
+//int      header;  /* true if block header must be written */
+{
+  bi_windup(s);        /* align on byte boundary */
+
+  if (header) {
+    put_short(s, len);
+    put_short(s, ~len);
+  }
+//  while (len--) {
+//    put_byte(s, *buf++);
+//  }
+  utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
+  s.pending += len;
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+function smaller(tree, n, m, depth) {
+  var _n2 = n * 2;
+  var _m2 = m * 2;
+  return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
+         (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
+}
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+function pqdownheap(s, tree, k)
+//    deflate_state *s;
+//    ct_data *tree;  /* the tree to restore */
+//    int k;               /* node to move down */
+{
+  var v = s.heap[k];
+  var j = k << 1;  /* left son of k */
+  while (j <= s.heap_len) {
+    /* Set j to the smallest of the two sons: */
+    if (j < s.heap_len &&
+      smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
+      j++;
+    }
+    /* Exit if v is smaller than both sons */
+    if (smaller(tree, v, s.heap[j], s.depth)) { break; }
+
+    /* Exchange v with the smallest son */
+    s.heap[k] = s.heap[j];
+    k = j;
+
+    /* And continue down the tree, setting j to the left son of k */
+    j <<= 1;
+  }
+  s.heap[k] = v;
+}
+
+
+// inlined manually
+// var SMALLEST = 1;
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+function compress_block(s, ltree, dtree)
+//    deflate_state *s;
+//    const ct_data *ltree; /* literal tree */
+//    const ct_data *dtree; /* distance tree */
+{
+  var dist;           /* distance of matched string */
+  var lc;             /* match length or unmatched char (if dist == 0) */
+  var lx = 0;         /* running index in l_buf */
+  var code;           /* the code to send */
+  var extra;          /* number of extra bits to send */
+
+  if (s.last_lit !== 0) {
+    do {
+      dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]);
+      lc = s.pending_buf[s.l_buf + lx];
+      lx++;
+
+      if (dist === 0) {
+        send_code(s, lc, ltree); /* send a literal byte */
+        //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+      } else {
+        /* Here, lc is the match length - MIN_MATCH */
+        code = _length_code[lc];
+        send_code(s, code + LITERALS + 1, ltree); /* send the length code */
+        extra = extra_lbits[code];
+        if (extra !== 0) {
+          lc -= base_length[code];
+          send_bits(s, lc, extra);       /* send the extra length bits */
+        }
+        dist--; /* dist is now the match distance - 1 */
+        code = d_code(dist);
+        //Assert (code < D_CODES, "bad d_code");
+
+        send_code(s, code, dtree);       /* send the distance code */
+        extra = extra_dbits[code];
+        if (extra !== 0) {
+          dist -= base_dist[code];
+          send_bits(s, dist, extra);   /* send the extra distance bits */
+        }
+      } /* literal or match pair ? */
+
+      /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+      //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+      //       "pendingBuf overflow");
+
+    } while (lx < s.last_lit);
+  }
+
+  send_code(s, END_BLOCK, ltree);
+}
+
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+function build_tree(s, desc)
+//    deflate_state *s;
+//    tree_desc *desc; /* the tree descriptor */
+{
+  var tree     = desc.dyn_tree;
+  var stree    = desc.stat_desc.static_tree;
+  var has_stree = desc.stat_desc.has_stree;
+  var elems    = desc.stat_desc.elems;
+  var n, m;          /* iterate over heap elements */
+  var max_code = -1; /* largest code with non zero frequency */
+  var node;          /* new node being created */
+
+  /* Construct the initial heap, with least frequent element in
+   * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+   * heap[0] is not used.
+   */
+  s.heap_len = 0;
+  s.heap_max = HEAP_SIZE;
+
+  for (n = 0; n < elems; n++) {
+    if (tree[n * 2]/*.Freq*/ !== 0) {
+      s.heap[++s.heap_len] = max_code = n;
+      s.depth[n] = 0;
+
+    } else {
+      tree[n * 2 + 1]/*.Len*/ = 0;
+    }
+  }
+
+  /* The pkzip format requires that at least one distance code exists,
+   * and that at least one bit should be sent even if there is only one
+   * possible code. So to avoid special checks later on we force at least
+   * two codes of non zero frequency.
+   */
+  while (s.heap_len < 2) {
+    node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
+    tree[node * 2]/*.Freq*/ = 1;
+    s.depth[node] = 0;
+    s.opt_len--;
+
+    if (has_stree) {
+      s.static_len -= stree[node * 2 + 1]/*.Len*/;
+    }
+    /* node is 0 or 1 so it does not have extra bits */
+  }
+  desc.max_code = max_code;
+
+  /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+   * establish sub-heaps of increasing lengths:
+   */
+  for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
+
+  /* Construct the Huffman tree by repeatedly combining the least two
+   * frequent nodes.
+   */
+  node = elems;              /* next internal node of the tree */
+  do {
+    //pqremove(s, tree, n);  /* n = node of least frequency */
+    /*** pqremove ***/
+    n = s.heap[1/*SMALLEST*/];
+    s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
+    pqdownheap(s, tree, 1/*SMALLEST*/);
+    /***/
+
+    m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
+
+    s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
+    s.heap[--s.heap_max] = m;
+
+    /* Create a new node father of n and m */
+    tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
+    s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
+    tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
+
+    /* and insert the new node in the heap */
+    s.heap[1/*SMALLEST*/] = node++;
+    pqdownheap(s, tree, 1/*SMALLEST*/);
+
+  } while (s.heap_len >= 2);
+
+  s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
+
+  /* At this point, the fields freq and dad are set. We can now
+   * generate the bit lengths.
+   */
+  gen_bitlen(s, desc);
+
+  /* The field len is now set, we can generate the bit codes */
+  gen_codes(tree, max_code, s.bl_count);
+}
+
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+function scan_tree(s, tree, max_code)
+//    deflate_state *s;
+//    ct_data *tree;   /* the tree to be scanned */
+//    int max_code;    /* and its largest code of non zero frequency */
+{
+  var n;                     /* iterates over all tree elements */
+  var prevlen = -1;          /* last emitted length */
+  var curlen;                /* length of current code */
+
+  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
+
+  var count = 0;             /* repeat count of the current code */
+  var max_count = 7;         /* max repeat count */
+  var min_count = 4;         /* min repeat count */
+
+  if (nextlen === 0) {
+    max_count = 138;
+    min_count = 3;
+  }
+  tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
+
+  for (n = 0; n <= max_code; n++) {
+    curlen = nextlen;
+    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
+
+    if (++count < max_count && curlen === nextlen) {
+      continue;
+
+    } else if (count < min_count) {
+      s.bl_tree[curlen * 2]/*.Freq*/ += count;
+
+    } else if (curlen !== 0) {
+
+      if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
+      s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
+
+    } else if (count <= 10) {
+      s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
+
+    } else {
+      s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
+    }
+
+    count = 0;
+    prevlen = curlen;
+
+    if (nextlen === 0) {
+      max_count = 138;
+      min_count = 3;
+
+    } else if (curlen === nextlen) {
+      max_count = 6;
+      min_count = 3;
+
+    } else {
+      max_count = 7;
+      min_count = 4;
+    }
+  }
+}
+
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+function send_tree(s, tree, max_code)
+//    deflate_state *s;
+//    ct_data *tree; /* the tree to be scanned */
+//    int max_code;       /* and its largest code of non zero frequency */
+{
+  var n;                     /* iterates over all tree elements */
+  var prevlen = -1;          /* last emitted length */
+  var curlen;                /* length of current code */
+
+  var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
+
+  var count = 0;             /* repeat count of the current code */
+  var max_count = 7;         /* max repeat count */
+  var min_count = 4;         /* min repeat count */
+
+  /* tree[max_code+1].Len = -1; */  /* guard already set */
+  if (nextlen === 0) {
+    max_count = 138;
+    min_count = 3;
+  }
+
+  for (n = 0; n <= max_code; n++) {
+    curlen = nextlen;
+    nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
+
+    if (++count < max_count && curlen === nextlen) {
+      continue;
+
+    } else if (count < min_count) {
+      do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
+
+    } else if (curlen !== 0) {
+      if (curlen !== prevlen) {
+        send_code(s, curlen, s.bl_tree);
+        count--;
+      }
+      //Assert(count >= 3 && count <= 6, " 3_6?");
+      send_code(s, REP_3_6, s.bl_tree);
+      send_bits(s, count - 3, 2);
+
+    } else if (count <= 10) {
+      send_code(s, REPZ_3_10, s.bl_tree);
+      send_bits(s, count - 3, 3);
+
+    } else {
+      send_code(s, REPZ_11_138, s.bl_tree);
+      send_bits(s, count - 11, 7);
+    }
+
+    count = 0;
+    prevlen = curlen;
+    if (nextlen === 0) {
+      max_count = 138;
+      min_count = 3;
+
+    } else if (curlen === nextlen) {
+      max_count = 6;
+      min_count = 3;
+
+    } else {
+      max_count = 7;
+      min_count = 4;
+    }
+  }
+}
+
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+function build_bl_tree(s) {
+  var max_blindex;  /* index of last bit length code of non zero freq */
+
+  /* Determine the bit length frequencies for literal and distance trees */
+  scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
+  scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
+
+  /* Build the bit length tree: */
+  build_tree(s, s.bl_desc);
+  /* opt_len now includes the length of the tree representations, except
+   * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+   */
+
+  /* Determine the number of bit length codes to send. The pkzip format
+   * requires that at least 4 bit length codes be sent. (appnote.txt says
+   * 3 but the actual value used is 4.)
+   */
+  for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
+    if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
+      break;
+    }
+  }
+  /* Update opt_len to include the bit length tree and counts */
+  s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
+  //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+  //        s->opt_len, s->static_len));
+
+  return max_blindex;
+}
+
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+function send_all_trees(s, lcodes, dcodes, blcodes)
+//    deflate_state *s;
+//    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+  var rank;                    /* index in bl_order */
+
+  //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+  //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+  //        "too many codes");
+  //Tracev((stderr, "\nbl counts: "));
+  send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
+  send_bits(s, dcodes - 1,   5);
+  send_bits(s, blcodes - 4,  4); /* not -3 as stated in appnote.txt */
+  for (rank = 0; rank < blcodes; rank++) {
+    //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+    send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
+  }
+  //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+  send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
+  //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+  send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
+  //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ *   "gray list" that is ignored in this detection algorithm:
+ *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+function detect_data_type(s) {
+  /* black_mask is the bit mask of black-listed bytes
+   * set bits 0..6, 14..25, and 28..31
+   * 0xf3ffc07f = binary 11110011111111111100000001111111
+   */
+  var black_mask = 0xf3ffc07f;
+  var n;
+
+  /* Check for non-textual ("black-listed") bytes. */
+  for (n = 0; n <= 31; n++, black_mask >>>= 1) {
+    if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) {
+      return Z_BINARY;
+    }
+  }
+
+  /* Check for textual ("white-listed") bytes. */
+  if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
+      s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
+    return Z_TEXT;
+  }
+  for (n = 32; n < LITERALS; n++) {
+    if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
+      return Z_TEXT;
+    }
+  }
+
+  /* There are no "black-listed" or "white-listed" bytes:
+   * this stream either is empty or has tolerated ("gray-listed") bytes only.
+   */
+  return Z_BINARY;
+}
+
+
+var static_init_done = false;
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+function _tr_init(s)
+{
+
+  if (!static_init_done) {
+    tr_static_init();
+    static_init_done = true;
+  }
+
+  s.l_desc  = new TreeDesc(s.dyn_ltree, static_l_desc);
+  s.d_desc  = new TreeDesc(s.dyn_dtree, static_d_desc);
+  s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
+
+  s.bi_buf = 0;
+  s.bi_valid = 0;
+
+  /* Initialize the first block of the first file: */
+  init_block(s);
+}
+
+
+/* ===========================================================================
+ * Send a stored block
+ */
+function _tr_stored_block(s, buf, stored_len, last)
+//DeflateState *s;
+//charf *buf;       /* input block */
+//ulg stored_len;   /* length of input block */
+//int last;         /* one if this is the last block for a file */
+{
+  send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3);    /* send block type */
+  copy_block(s, buf, stored_len, true); /* with header */
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+function _tr_align(s) {
+  send_bits(s, STATIC_TREES << 1, 3);
+  send_code(s, END_BLOCK, static_ltree);
+  bi_flush(s);
+}
+
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+function _tr_flush_block(s, buf, stored_len, last)
+//DeflateState *s;
+//charf *buf;       /* input block, or NULL if too old */
+//ulg stored_len;   /* length of input block */
+//int last;         /* one if this is the last block for a file */
+{
+  var opt_lenb, static_lenb;  /* opt_len and static_len in bytes */
+  var max_blindex = 0;        /* index of last bit length code of non zero freq */
+
+  /* Build the Huffman trees unless a stored block is forced */
+  if (s.level > 0) {
+
+    /* Check if the file is binary or text */
+    if (s.strm.data_type === Z_UNKNOWN) {
+      s.strm.data_type = detect_data_type(s);
+    }
+
+    /* Construct the literal and distance trees */
+    build_tree(s, s.l_desc);
+    // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+    //        s->static_len));
+
+    build_tree(s, s.d_desc);
+    // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+    //        s->static_len));
+    /* At this point, opt_len and static_len are the total bit lengths of
+     * the compressed block data, excluding the tree representations.
+     */
+
+    /* Build the bit length tree for the above two trees, and get the index
+     * in bl_order of the last bit length code to send.
+     */
+    max_blindex = build_bl_tree(s);
+
+    /* Determine the best encoding. Compute the block lengths in bytes. */
+    opt_lenb = (s.opt_len + 3 + 7) >>> 3;
+    static_lenb = (s.static_len + 3 + 7) >>> 3;
+
+    // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+    //        opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+    //        s->last_lit));
+
+    if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
+
+  } else {
+    // Assert(buf != (char*)0, "lost buf");
+    opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+  }
+
+  if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) {
+    /* 4: two words for the lengths */
+
+    /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+     * Otherwise we can't have processed more than WSIZE input bytes since
+     * the last block flush, because compression would have been
+     * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+     * transform a block into a stored block.
+     */
+    _tr_stored_block(s, buf, stored_len, last);
+
+  } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
+
+    send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
+    compress_block(s, static_ltree, static_dtree);
+
+  } else {
+    send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
+    send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
+    compress_block(s, s.dyn_ltree, s.dyn_dtree);
+  }
+  // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+  /* The above check is made mod 2^32, for files larger than 512 MB
+   * and uLong implemented on 32 bits.
+   */
+  init_block(s);
+
+  if (last) {
+    bi_windup(s);
+  }
+  // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+  //       s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+function _tr_tally(s, dist, lc)
+//    deflate_state *s;
+//    unsigned dist;  /* distance of matched string */
+//    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+  //var out_length, in_length, dcode;
+
+  s.pending_buf[s.d_buf + s.last_lit * 2]     = (dist >>> 8) & 0xff;
+  s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
+
+  s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
+  s.last_lit++;
+
+  if (dist === 0) {
+    /* lc is the unmatched char */
+    s.dyn_ltree[lc * 2]/*.Freq*/++;
+  } else {
+    s.matches++;
+    /* Here, lc is the match length - MIN_MATCH */
+    dist--;             /* dist = match distance - 1 */
+    //Assert((ush)dist < (ush)MAX_DIST(s) &&
+    //       (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+    //       (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+    s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;
+    s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
+  }
+
+// (!) This block is disabled in zlib defailts,
+// don't enable it for binary compatibility
+
+//#ifdef TRUNCATE_BLOCK
+//  /* Try to guess if it is profitable to stop the current block here */
+//  if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
+//    /* Compute an upper bound for the compressed length */
+//    out_length = s.last_lit*8;
+//    in_length = s.strstart - s.block_start;
+//
+//    for (dcode = 0; dcode < D_CODES; dcode++) {
+//      out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
+//    }
+//    out_length >>>= 3;
+//    //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+//    //       s->last_lit, in_length, out_length,
+//    //       100L - out_length*100L/in_length));
+//    if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
+//      return true;
+//    }
+//  }
+//#endif
+
+  return (s.last_lit === s.lit_bufsize - 1);
+  /* We avoid equality with lit_bufsize because of wraparound at 64K
+   * on 16 bit machines and because stored blocks are restricted to
+   * 64K-1 bytes.
+   */
+}
+
+exports._tr_init  = _tr_init;
+exports._tr_stored_block = _tr_stored_block;
+exports._tr_flush_block  = _tr_flush_block;
+exports._tr_tally = _tr_tally;
+exports._tr_align = _tr_align;
+
+},{"../utils/common":41}],53:[function(require,module,exports){
+'use strict';
+
+// (C) 1995-2013 Jean-loup Gailly and Mark Adler
+// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+//   claim that you wrote the original software. If you use this software
+//   in a product, an acknowledgment in the product documentation would be
+//   appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+//   misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+function ZStream() {
+  /* next input byte */
+  this.input = null; // JS specific, because we have no pointers
+  this.next_in = 0;
+  /* number of bytes available at input */
+  this.avail_in = 0;
+  /* total number of input bytes read so far */
+  this.total_in = 0;
+  /* next output byte should be put there */
+  this.output = null; // JS specific, because we have no pointers
+  this.next_out = 0;
+  /* remaining free space at output */
+  this.avail_out = 0;
+  /* total number of bytes output so far */
+  this.total_out = 0;
+  /* last error message, NULL if no error */
+  this.msg = ''/*Z_NULL*/;
+  /* not visible by applications */
+  this.state = null;
+  /* best guess about the data type: binary or text */
+  this.data_type = 2/*Z_UNKNOWN*/;
+  /* adler32 value of the uncompressed data */
+  this.adler = 0;
+}
+
+module.exports = ZStream;
+
+},{}],54:[function(require,module,exports){
+'use strict';
+module.exports = typeof setImmediate === 'function' ? setImmediate :
+       function setImmediate() {
+               var args = [].slice.apply(arguments);
+               args.splice(1, 0, 0);
+               setTimeout.apply(null, args);
+       };
+
+},{}]},{},[10])(10)
+});
\ No newline at end of file
diff --git a/java/doc/jquery/jszip/dist/jszip.min.js b/java/doc/jquery/jszip/dist/jszip.min.js
new file mode 100644 (file)
index 0000000..6c4645c
--- /dev/null
@@ -0,0 +1,13 @@
+/*!
+
+JSZip v3.7.1 - A JavaScript class for generating and reading zip files
+<http://stuartk.com/jszip>
+
+(c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
+Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.
+
+JSZip uses the library pako released under the MIT license :
+https://github.com/nodeca/pako/blob/master/LICENSE
+*/
+
+!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=t()}}(function(){return function s(a,o,h){function u(r,t){if(!o[r]){if(!a[r]){var e="function"==typeof require&&require;if(!t&&e)return e(r,!0);if(l)return l(r,!0);var i=new Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}var n=o[r]={exports:{}};a[r][0].call(n.exports,function(t){var e=a[r][1][t];return u(e||t)},n,n.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,t=0;t<h.length;t++)u(h[t]);return u}({1:[function(t,e,r){"use strict";var c=t("./utils"),d=t("./support"),p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";r.encode=function(t){for(var e,r,i,n,s,a,o,h=[],u=0,l=t.length,f=l,d="string"!==c.getTypeOf(t);u<t.length;)f=l-u,i=d?(e=t[u++],r=u<l?t[u++]:0,u<l?t[u++]:0):(e=t.charCodeAt(u++),r=u<l?t.charCodeAt(u++):0,u<l?t.charCodeAt(u++):0),n=e>>2,s=(3&e)<<4|r>>4,a=1<f?(15&r)<<2|i>>6:64,o=2<f?63&i:64,h.push(p.charAt(n)+p.charAt(s)+p.charAt(a)+p.charAt(o));return h.join("")},r.decode=function(t){var e,r,i,n,s,a,o=0,h=0,u="data:";if(t.substr(0,u.length)===u)throw new Error("Invalid base64 input, it looks like a data url.");var l,f=3*(t=t.replace(/[^A-Za-z0-9\+\/\=]/g,"")).length/4;if(t.charAt(t.length-1)===p.charAt(64)&&f--,t.charAt(t.length-2)===p.charAt(64)&&f--,f%1!=0)throw new Error("Invalid base64 input, bad content length.");for(l=d.uint8array?new Uint8Array(0|f):new Array(0|f);o<t.length;)e=p.indexOf(t.charAt(o++))<<2|(n=p.indexOf(t.charAt(o++)))>>4,r=(15&n)<<4|(s=p.indexOf(t.charAt(o++)))>>2,i=(3&s)<<6|(a=p.indexOf(t.charAt(o++))),l[h++]=e,64!==s&&(l[h++]=r),64!==a&&(l[h++]=i);return l}},{"./support":30,"./utils":32}],2:[function(t,e,r){"use strict";var i=t("./external"),n=t("./stream/DataWorker"),s=t("./stream/Crc32Probe"),a=t("./stream/DataLengthProbe");function o(t,e,r,i,n){this.compressedSize=t,this.uncompressedSize=e,this.crc32=r,this.compression=i,this.compressedContent=n}o.prototype={getContentWorker:function(){var t=new n(i.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),e=this;return t.on("end",function(){if(this.streamInfo.data_length!==e.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),t},getCompressedWorker:function(){return new n(i.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(t,e,r){return t.pipe(new s).pipe(new a("uncompressedSize")).pipe(e.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",e)},e.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(t,e,r){"use strict";var i=t("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(t){return new i("STORE compression")},uncompressWorker:function(){return new i("STORE decompression")}},r.DEFLATE=t("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(t,e,r){"use strict";var i=t("./utils");var o=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e){return void 0!==t&&t.length?"string"!==i.getTypeOf(t)?function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e[a])];return-1^t}(0|e,t,t.length,0):function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e.charCodeAt(a))];return-1^t}(0|e,t,t.length,0):0}},{"./utils":32}],5:[function(t,e,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(t,e,r){"use strict";var i=null;i="undefined"!=typeof Promise?Promise:t("lie"),e.exports={Promise:i}},{lie:37}],7:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,n=t("pako"),s=t("./utils"),a=t("./stream/GenericWorker"),o=i?"uint8array":"array";function h(t,e){a.call(this,"FlateWorker/"+t),this._pako=null,this._pakoAction=t,this._pakoOptions=e,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(t){this.meta=t.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,t.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new n[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var e=this;this._pako.onData=function(t){e.push({data:t,meta:e.meta})}},r.compressWorker=function(t){return new h("Deflate",t)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(t,e,r){"use strict";function A(t,e){var r,i="";for(r=0;r<e;r++)i+=String.fromCharCode(255&t),t>>>=8;return i}function i(t,e,r,i,n,s){var a,o,h=t.file,u=t.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),d=I.transformTo("string",O.utf8encode(h.name)),c=h.comment,p=I.transformTo("string",s(c)),m=I.transformTo("string",O.utf8encode(c)),_=d.length!==h.name.length,g=m.length!==c.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};e&&!r||(x.crc32=t.crc32,x.compressedSize=t.compressedSize,x.uncompressedSize=t.uncompressedSize);var S=0;e&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===n?(C=798,z|=function(t,e){var r=t;return t||(r=e?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(t){return 63&(t||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+d,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(i,4)+f+b+p}}var I=t("../utils"),n=t("../stream/GenericWorker"),O=t("../utf8"),B=t("../crc32"),R=t("../signature");function s(t,e,r,i){n.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=e,this.zipPlatform=r,this.encodeFileName=i,this.streamFiles=t,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,n),s.prototype.push=function(t){var e=t.meta.percent||0,r=this.entriesCount,i=this._sources.length;this.accumulate?this.contentBuffer.push(t):(this.bytesWritten+=t.data.length,n.prototype.push.call(this,{data:t.data,meta:{currentFile:this.currentFile,percent:r?(e+100*(r-i-1))/r:100}}))},s.prototype.openedSource=function(t){this.currentSourceOffset=this.bytesWritten,this.currentFile=t.file.name;var e=this.streamFiles&&!t.file.dir;if(e){var r=i(t,e,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(t){this.accumulate=!1;var e=this.streamFiles&&!t.file.dir,r=i(t,e,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),e)this.push({data:function(t){return R.DATA_DESCRIPTOR+A(t.crc32,4)+A(t.compressedSize,4)+A(t.uncompressedSize,4)}(t),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var t=this.bytesWritten,e=0;e<this.dirRecords.length;e++)this.push({data:this.dirRecords[e],meta:{percent:100}});var r=this.bytesWritten-t,i=function(t,e,r,i,n){var s=I.transformTo("string",n(i));return R.CENTRAL_DIRECTORY_END+"\0\0\0\0"+A(t,2)+A(t,2)+A(e,4)+A(r,4)+A(s.length,2)+s}(this.dirRecords.length,r,t,this.zipComment,this.encodeFileName);this.push({data:i,meta:{percent:100}})},s.prototype.prepareNextSource=function(){this.previous=this._sources.shift(),this.openedSource(this.previous.streamInfo),this.isPaused?this.previous.pause():this.previous.resume()},s.prototype.registerPrevious=function(t){this._sources.push(t);var e=this;return t.on("data",function(t){e.processChunk(t)}),t.on("end",function(){e.closedSource(e.previous.streamInfo),e._sources.length?e.prepareNextSource():e.end()}),t.on("error",function(t){e.error(t)}),this},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this.previous&&this._sources.length?(this.prepareNextSource(),!0):this.previous||this._sources.length||this.generatedError?void 0:(this.end(),!0))},s.prototype.error=function(t){var e=this._sources;if(!n.prototype.error.call(this,t))return!1;for(var r=0;r<e.length;r++)try{e[r].error(t)}catch(t){}return!0},s.prototype.lock=function(){n.prototype.lock.call(this);for(var t=this._sources,e=0;e<t.length;e++)t[e].lock()},e.exports=s},{"../crc32":4,"../signature":23,"../stream/GenericWorker":28,"../utf8":31,"../utils":32}],9:[function(t,e,r){"use strict";var u=t("../compressions"),i=t("./ZipFileWorker");r.generateWorker=function(t,a,e){var o=new i(a.streamFiles,e,a.platform,a.encodeFileName),h=0;try{t.forEach(function(t,e){h++;var r=function(t,e){var r=t||e,i=u[r];if(!i)throw new Error(r+" is not a valid compression method !");return i}(e.options.compression,a.compression),i=e.options.compressionOptions||a.compressionOptions||{},n=e.dir,s=e.date;e._compressWorker(r,i).withStreamInfo("file",{name:t,dir:n,date:s,comment:e.comment||"",unixPermissions:e.unixPermissions,dosPermissions:e.dosPermissions}).pipe(o)}),o.entriesCount=h}catch(t){o.error(t)}return o}},{"../compressions":3,"./ZipFileWorker":8}],10:[function(t,e,r){"use strict";function i(){if(!(this instanceof i))return new i;if(arguments.length)throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");this.files=Object.create(null),this.comment=null,this.root="",this.clone=function(){var t=new i;for(var e in this)"function"!=typeof this[e]&&(t[e]=this[e]);return t}}(i.prototype=t("./object")).loadAsync=t("./load"),i.support=t("./support"),i.defaults=t("./defaults"),i.version="3.7.1",i.loadAsync=function(t,e){return(new i).loadAsync(t,e)},i.external=t("./external"),e.exports=i},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(t,e,r){"use strict";var i=t("./utils"),n=t("./external"),o=t("./utf8"),h=t("./zipEntries"),s=t("./stream/Crc32Probe"),u=t("./nodejsUtils");function l(i){return new n.Promise(function(t,e){var r=i.decompressed.getContentWorker().pipe(new s);r.on("error",function(t){e(t)}).on("end",function(){r.streamInfo.crc32!==i.decompressed.crc32?e(new Error("Corrupted zip : CRC32 mismatch")):t()}).resume()})}e.exports=function(t,s){var a=this;return s=i.extend(s||{},{base64:!1,checkCRC32:!1,optimizedBinaryString:!1,createFolders:!1,decodeFileName:o.utf8decode}),u.isNode&&u.isStream(t)?n.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file.")):i.prepareContent("the loaded zip file",t,!0,s.optimizedBinaryString,s.base64).then(function(t){var e=new h(s);return e.load(t),e}).then(function(t){var e=[n.Promise.resolve(t)],r=t.files;if(s.checkCRC32)for(var i=0;i<r.length;i++)e.push(l(r[i]));return n.Promise.all(e)}).then(function(t){for(var e=t.shift(),r=e.files,i=0;i<r.length;i++){var n=r[i];a.file(n.fileNameStr,n.decompressed,{binary:!0,optimizedBinaryString:!0,date:n.date,dir:n.dir,comment:n.fileCommentStr.length?n.fileCommentStr:null,unixPermissions:n.unixPermissions,dosPermissions:n.dosPermissions,createFolders:s.createFolders})}return e.zipComment.length&&(a.comment=e.zipComment),a})}},{"./external":6,"./nodejsUtils":14,"./stream/Crc32Probe":25,"./utf8":31,"./utils":32,"./zipEntries":33}],12:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../stream/GenericWorker");function s(t,e){n.call(this,"Nodejs stream input adapter for "+t),this._upstreamEnded=!1,this._bindStream(e)}i.inherits(s,n),s.prototype._bindStream=function(t){var e=this;(this._stream=t).pause(),t.on("data",function(t){e.push({data:t,meta:{percent:0}})}).on("error",function(t){e.isPaused?this.generatedError=t:e.error(t)}).on("end",function(){e.isPaused?e._upstreamEnded=!0:e.end()})},s.prototype.pause=function(){return!!n.prototype.pause.call(this)&&(this._stream.pause(),!0)},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(this._upstreamEnded?this.end():this._stream.resume(),!0)},e.exports=s},{"../stream/GenericWorker":28,"../utils":32}],13:[function(t,e,r){"use strict";var n=t("readable-stream").Readable;function i(t,e,r){n.call(this,e),this._helper=t;var i=this;t.on("data",function(t,e){i.push(t)||i._helper.pause(),r&&r(e)}).on("error",function(t){i.emit("error",t)}).on("end",function(){i.push(null)})}t("../utils").inherits(i,n),i.prototype._read=function(){this._helper.resume()},e.exports=i},{"../utils":32,"readable-stream":16}],14:[function(t,e,r){"use strict";e.exports={isNode:"undefined"!=typeof Buffer,newBufferFrom:function(t,e){if(Buffer.from&&Buffer.from!==Uint8Array.from)return Buffer.from(t,e);if("number"==typeof t)throw new Error('The "data" argument must not be a number');return new Buffer(t,e)},allocBuffer:function(t){if(Buffer.alloc)return Buffer.alloc(t);var e=new Buffer(t);return e.fill(0),e},isBuffer:function(t){return Buffer.isBuffer(t)},isStream:function(t){return t&&"function"==typeof t.on&&"function"==typeof t.pause&&"function"==typeof t.resume}}},{}],15:[function(t,e,r){"use strict";function s(t,e,r){var i,n=u.getTypeOf(e),s=u.extend(r||{},f);s.date=s.date||new Date,null!==s.compression&&(s.compression=s.compression.toUpperCase()),"string"==typeof s.unixPermissions&&(s.unixPermissions=parseInt(s.unixPermissions,8)),s.unixPermissions&&16384&s.unixPermissions&&(s.dir=!0),s.dosPermissions&&16&s.dosPermissions&&(s.dir=!0),s.dir&&(t=g(t)),s.createFolders&&(i=_(t))&&b.call(this,i,!0);var a="string"===n&&!1===s.binary&&!1===s.base64;r&&void 0!==r.binary||(s.binary=!a),(e instanceof d&&0===e.uncompressedSize||s.dir||!e||0===e.length)&&(s.base64=!1,s.binary=!0,e="",s.compression="STORE",n="string");var o=null;o=e instanceof d||e instanceof l?e:p.isNode&&p.isStream(e)?new m(t,e):u.prepareContent(t,e,s.binary,s.optimizedBinaryString,s.base64);var h=new c(t,o,s);this.files[t]=h}var n=t("./utf8"),u=t("./utils"),l=t("./stream/GenericWorker"),a=t("./stream/StreamHelper"),f=t("./defaults"),d=t("./compressedObject"),c=t("./zipObject"),o=t("./generate"),p=t("./nodejsUtils"),m=t("./nodejs/NodejsStreamInputAdapter"),_=function(t){"/"===t.slice(-1)&&(t=t.substring(0,t.length-1));var e=t.lastIndexOf("/");return 0<e?t.substring(0,e):""},g=function(t){return"/"!==t.slice(-1)&&(t+="/"),t},b=function(t,e){return e=void 0!==e?e:f.createFolders,t=g(t),this.files[t]||s.call(this,t,null,{dir:!0,createFolders:e}),this.files[t]};function h(t){return"[object RegExp]"===Object.prototype.toString.call(t)}var i={load:function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},forEach:function(t){var e,r,i;for(e in this.files)i=this.files[e],(r=e.slice(this.root.length,e.length))&&e.slice(0,this.root.length)===this.root&&t(r,i)},filter:function(r){var i=[];return this.forEach(function(t,e){r(t,e)&&i.push(e)}),i},file:function(t,e,r){if(1!==arguments.length)return t=this.root+t,s.call(this,t,e,r),this;if(h(t)){var i=t;return this.filter(function(t,e){return!e.dir&&i.test(t)})}var n=this.files[this.root+t];return n&&!n.dir?n:null},folder:function(r){if(!r)return this;if(h(r))return this.filter(function(t,e){return e.dir&&r.test(t)});var t=this.root+r,e=b.call(this,t),i=this.clone();return i.root=e.name,i},remove:function(r){r=this.root+r;var t=this.files[r];if(t||("/"!==r.slice(-1)&&(r+="/"),t=this.files[r]),t&&!t.dir)delete this.files[r];else for(var e=this.filter(function(t,e){return e.name.slice(0,r.length)===r}),i=0;i<e.length;i++)delete this.files[e[i].name];return this},generate:function(t){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},generateInternalStream:function(t){var e,r={};try{if((r=u.extend(t||{},{streamFiles:!1,compression:"STORE",compressionOptions:null,type:"",platform:"DOS",comment:null,mimeType:"application/zip",encodeFileName:n.utf8encode})).type=r.type.toLowerCase(),r.compression=r.compression.toUpperCase(),"binarystring"===r.type&&(r.type="string"),!r.type)throw new Error("No output type specified.");u.checkSupport(r.type),"darwin"!==r.platform&&"freebsd"!==r.platform&&"linux"!==r.platform&&"sunos"!==r.platform||(r.platform="UNIX"),"win32"===r.platform&&(r.platform="DOS");var i=r.comment||this.comment||"";e=o.generateWorker(this,r,i)}catch(t){(e=new l("error")).error(t)}return new a(e,r.type||"string",r.mimeType)},generateAsync:function(t,e){return this.generateInternalStream(t).accumulate(e)},generateNodeStream:function(t,e){return(t=t||{}).type||(t.type="nodebuffer"),this.generateInternalStream(t).toNodejsStream(e)}};e.exports=i},{"./compressedObject":2,"./defaults":5,"./generate":9,"./nodejs/NodejsStreamInputAdapter":12,"./nodejsUtils":14,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31,"./utils":32,"./zipObject":35}],16:[function(t,e,r){e.exports=t("stream")},{stream:void 0}],17:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t);for(var e=0;e<this.data.length;e++)t[e]=255&t[e]}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data[this.zero+t]},n.prototype.lastIndexOfSignature=function(t){for(var e=t.charCodeAt(0),r=t.charCodeAt(1),i=t.charCodeAt(2),n=t.charCodeAt(3),s=this.length-4;0<=s;--s)if(this.data[s]===e&&this.data[s+1]===r&&this.data[s+2]===i&&this.data[s+3]===n)return s-this.zero;return-1},n.prototype.readAndCheckSignature=function(t){var e=t.charCodeAt(0),r=t.charCodeAt(1),i=t.charCodeAt(2),n=t.charCodeAt(3),s=this.readData(4);return e===s[0]&&r===s[1]&&i===s[2]&&n===s[3]},n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return[];var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],18:[function(t,e,r){"use strict";var i=t("../utils");function n(t){this.data=t,this.length=t.length,this.index=0,this.zero=0}n.prototype={checkOffset:function(t){this.checkIndex(this.index+t)},checkIndex:function(t){if(this.length<this.zero+t||t<0)throw new Error("End of data reached (data length = "+this.length+", asked index = "+t+"). Corrupted zip ?")},setIndex:function(t){this.checkIndex(t),this.index=t},skip:function(t){this.setIndex(this.index+t)},byteAt:function(t){},readInt:function(t){var e,r=0;for(this.checkOffset(t),e=this.index+t-1;e>=this.index;e--)r=(r<<8)+this.byteAt(e);return this.index+=t,r},readString:function(t){return i.transformTo("string",this.readData(t))},readData:function(t){},lastIndexOfSignature:function(t){},readAndCheckSignature:function(t){},readDate:function(){var t=this.readInt(4);return new Date(Date.UTC(1980+(t>>25&127),(t>>21&15)-1,t>>16&31,t>>11&31,t>>5&63,(31&t)<<1))}},e.exports=n},{"../utils":32}],19:[function(t,e,r){"use strict";var i=t("./Uint8ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data.charCodeAt(this.zero+t)},n.prototype.lastIndexOfSignature=function(t){return this.data.lastIndexOf(t)-this.zero},n.prototype.readAndCheckSignature=function(t){return t===this.readData(4)},n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],21:[function(t,e,r){"use strict";var i=t("./ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return new Uint8Array(0);var e=this.data.subarray(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./ArrayReader":17}],22:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../support"),s=t("./ArrayReader"),a=t("./StringReader"),o=t("./NodeBufferReader"),h=t("./Uint8ArrayReader");e.exports=function(t){var e=i.getTypeOf(t);return i.checkSupport(e),"string"!==e||n.uint8array?"nodebuffer"===e?new o(t):n.uint8array?new h(i.transformTo("uint8array",t)):new s(i.transformTo("array",t)):new a(t)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(t,e,r){"use strict";r.LOCAL_FILE_HEADER="PK\ 3\ 4",r.CENTRAL_FILE_HEADER="PK\ 1\ 2",r.CENTRAL_DIRECTORY_END="PK\ 5\ 6",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK\ 6\a",r.ZIP64_CENTRAL_DIRECTORY_END="PK\ 6\ 6",r.DATA_DESCRIPTOR="PK\a\b"},{}],24:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../utils");function s(t){i.call(this,"ConvertWorker to "+t),this.destType=t}n.inherits(s,i),s.prototype.processChunk=function(t){this.push({data:n.transformTo(this.destType,t.data),meta:t.meta})},e.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../crc32");function s(){i.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}t("../utils").inherits(s,i),s.prototype.processChunk=function(t){this.streamInfo.crc32=n(t.data,this.streamInfo.crc32||0),this.push(t)},e.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataLengthProbe for "+t),this.propName=t,this.withStreamInfo(t,0)}i.inherits(s,n),s.prototype.processChunk=function(t){if(t){var e=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=e+t.data.length}n.prototype.processChunk.call(this,t)},e.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataWorker");var e=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,t.then(function(t){e.dataIsReady=!0,e.data=t,e.max=t&&t.length||0,e.type=i.getTypeOf(t),e.isPaused||e._tickAndRepeat()},function(t){e.error(t)})}i.inherits(s,n),s.prototype.cleanUp=function(){n.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,i.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(i.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var t=null,e=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":t=this.data.substring(this.index,e);break;case"uint8array":t=this.data.subarray(this.index,e);break;case"array":case"nodebuffer":t=this.data.slice(this.index,e)}return this.index=e,this.push({data:t,meta:{percent:this.max?this.index/this.max*100:0}})},e.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(t,e,r){"use strict";function i(t){this.name=t||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}i.prototype={push:function(t){this.emit("data",t)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(t){this.emit("error",t)}return!0},error:function(t){return!this.isFinished&&(this.isPaused?this.generatedError=t:(this.isFinished=!0,this.emit("error",t),this.previous&&this.previous.error(t),this.cleanUp()),!0)},on:function(t,e){return this._listeners[t].push(e),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(t,e){if(this._listeners[t])for(var r=0;r<this._listeners[t].length;r++)this._listeners[t][r].call(this,e)},pipe:function(t){return t.registerPrevious(this)},registerPrevious:function(t){if(this.isLocked)throw new Error("The stream '"+this+"' has already been used.");this.streamInfo=t.streamInfo,this.mergeStreamInfo(),this.previous=t;var e=this;return t.on("data",function(t){e.processChunk(t)}),t.on("end",function(){e.end()}),t.on("error",function(t){e.error(t)}),this},pause:function(){return!this.isPaused&&!this.isFinished&&(this.isPaused=!0,this.previous&&this.previous.pause(),!0)},resume:function(){if(!this.isPaused||this.isFinished)return!1;var t=this.isPaused=!1;return this.generatedError&&(this.error(this.generatedError),t=!0),this.previous&&this.previous.resume(),!t},flush:function(){},processChunk:function(t){this.push(t)},withStreamInfo:function(t,e){return this.extraStreamInfo[t]=e,this.mergeStreamInfo(),this},mergeStreamInfo:function(){for(var t in this.extraStreamInfo)this.extraStreamInfo.hasOwnProperty(t)&&(this.streamInfo[t]=this.extraStreamInfo[t])},lock:function(){if(this.isLocked)throw new Error("The stream '"+this+"' has already been used.");this.isLocked=!0,this.previous&&this.previous.lock()},toString:function(){var t="Worker "+this.name;return this.previous?this.previous+" -> "+t:t}},e.exports=i},{}],29:[function(t,e,r){"use strict";var h=t("../utils"),n=t("./ConvertWorker"),s=t("./GenericWorker"),u=t("../base64"),i=t("../support"),a=t("../external"),o=null;if(i.nodestream)try{o=t("../nodejs/NodejsStreamOutputAdapter")}catch(t){}function l(t,o){return new a.Promise(function(e,r){var i=[],n=t._internalType,s=t._outputType,a=t._mimeType;t.on("data",function(t,e){i.push(t),o&&o(e)}).on("error",function(t){i=[],r(t)}).on("end",function(){try{var t=function(t,e,r){switch(t){case"blob":return h.newBlob(h.transformTo("arraybuffer",e),r);case"base64":return u.encode(e);default:return h.transformTo(t,e)}}(s,function(t,e){var r,i=0,n=null,s=0;for(r=0;r<e.length;r++)s+=e[r].length;switch(t){case"string":return e.join("");case"array":return Array.prototype.concat.apply([],e);case"uint8array":for(n=new Uint8Array(s),r=0;r<e.length;r++)n.set(e[r],i),i+=e[r].length;return n;case"nodebuffer":return Buffer.concat(e);default:throw new Error("concat : unsupported type '"+t+"'")}}(n,i),a);e(t)}catch(t){r(t)}i=[]}).resume()})}function f(t,e,r){var i=e;switch(e){case"blob":case"arraybuffer":i="uint8array";break;case"base64":i="string"}try{this._internalType=i,this._outputType=e,this._mimeType=r,h.checkSupport(i),this._worker=t.pipe(new n(i)),t.lock()}catch(t){this._worker=new s("error"),this._worker.error(t)}}f.prototype={accumulate:function(t){return l(this,t)},on:function(t,e){var r=this;return"data"===t?this._worker.on(t,function(t){e.call(r,t.data,t.meta)}):this._worker.on(t,function(){h.delay(e,arguments,r)}),this},resume:function(){return h.delay(this._worker.resume,[],this._worker),this},pause:function(){return this._worker.pause(),this},toNodejsStream:function(t){if(h.checkSupport("nodestream"),"nodebuffer"!==this._outputType)throw new Error(this._outputType+" is not supported by this method");return new o(this,{objectMode:"nodebuffer"!==this._outputType},t)}},e.exports=f},{"../base64":1,"../external":6,"../nodejs/NodejsStreamOutputAdapter":13,"../support":30,"../utils":32,"./ConvertWorker":24,"./GenericWorker":28}],30:[function(t,e,r){"use strict";if(r.base64=!0,r.array=!0,r.string=!0,r.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,r.nodebuffer="undefined"!=typeof Buffer,r.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)r.blob=!1;else{var i=new ArrayBuffer(0);try{r.blob=0===new Blob([i],{type:"application/zip"}).size}catch(t){try{var n=new(self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder);n.append(i),r.blob=0===n.getBlob("application/zip").size}catch(t){r.blob=!1}}}try{r.nodestream=!!t("readable-stream").Readable}catch(t){r.nodestream=!1}},{"readable-stream":16}],31:[function(t,e,s){"use strict";for(var o=t("./utils"),h=t("./support"),r=t("./nodejsUtils"),i=t("./stream/GenericWorker"),u=new Array(256),n=0;n<256;n++)u[n]=252<=n?6:248<=n?5:240<=n?4:224<=n?3:192<=n?2:1;u[254]=u[254]=1;function a(){i.call(this,"utf-8 decode"),this.leftOver=null}function l(){i.call(this,"utf-8 encode")}s.utf8encode=function(t){return h.nodebuffer?r.newBufferFrom(t,"utf-8"):function(t){var e,r,i,n,s,a=t.length,o=0;for(n=0;n<a;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),o+=r<128?1:r<2048?2:r<65536?3:4;for(e=h.uint8array?new Uint8Array(o):new Array(o),n=s=0;s<o;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),r<128?e[s++]=r:(r<2048?e[s++]=192|r>>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e}(t)},s.utf8decode=function(t){return h.nodebuffer?o.transformTo("nodebuffer",t).toString("utf-8"):function(t){var e,r,i,n,s=t.length,a=new Array(2*s);for(e=r=0;e<s;)if((i=t[e++])<128)a[r++]=i;else if(4<(n=u[i]))a[r++]=65533,e+=n-1;else{for(i&=2===n?31:3===n?15:7;1<n&&e<s;)i=i<<6|63&t[e++],n--;1<n?a[r++]=65533:i<65536?a[r++]=i:(i-=65536,a[r++]=55296|i>>10&1023,a[r++]=56320|1023&i)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(t=o.transformTo(h.uint8array?"uint8array":"array",t))},o.inherits(a,i),a.prototype.processChunk=function(t){var e=o.transformTo(h.uint8array?"uint8array":"array",t.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=e;(e=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),e.set(r,this.leftOver.length)}else e=this.leftOver.concat(e);this.leftOver=null}var i=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}(e),n=e;i!==e.length&&(h.uint8array?(n=e.subarray(0,i),this.leftOver=e.subarray(i,e.length)):(n=e.slice(0,i),this.leftOver=e.slice(i,e.length))),this.push({data:s.utf8decode(n),meta:t.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,i),l.prototype.processChunk=function(t){this.push({data:s.utf8encode(t.data),meta:t.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(t,e,a){"use strict";var o=t("./support"),h=t("./base64"),r=t("./nodejsUtils"),i=t("set-immediate-shim"),u=t("./external");function n(t){return t}function l(t,e){for(var r=0;r<t.length;++r)e[r]=255&t.charCodeAt(r);return e}a.newBlob=function(e,r){a.checkSupport("blob");try{return new Blob([e],{type:r})}catch(t){try{var i=new(self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder);return i.append(e),i.getBlob(r)}catch(t){throw new Error("Bug : can't construct the Blob.")}}};var s={stringifyByChunk:function(t,e,r){var i=[],n=0,s=t.length;if(s<=r)return String.fromCharCode.apply(null,t);for(;n<s;)"array"===e||"nodebuffer"===e?i.push(String.fromCharCode.apply(null,t.slice(n,Math.min(n+r,s)))):i.push(String.fromCharCode.apply(null,t.subarray(n,Math.min(n+r,s)))),n+=r;return i.join("")},stringifyByChar:function(t){for(var e="",r=0;r<t.length;r++)e+=String.fromCharCode(t[r]);return e},applyCanBeUsed:{uint8array:function(){try{return o.uint8array&&1===String.fromCharCode.apply(null,new Uint8Array(1)).length}catch(t){return!1}}(),nodebuffer:function(){try{return o.nodebuffer&&1===String.fromCharCode.apply(null,r.allocBuffer(1)).length}catch(t){return!1}}()}};function f(t){var e=65536,r=a.getTypeOf(t),i=!0;if("uint8array"===r?i=s.applyCanBeUsed.uint8array:"nodebuffer"===r&&(i=s.applyCanBeUsed.nodebuffer),i)for(;1<e;)try{return s.stringifyByChunk(t,r,e)}catch(t){e=Math.floor(e/2)}return s.stringifyByChar(t)}function d(t,e){for(var r=0;r<t.length;r++)e[r]=t[r];return e}a.applyFromCharCode=f;var c={};c.string={string:n,array:function(t){return l(t,new Array(t.length))},arraybuffer:function(t){return c.string.uint8array(t).buffer},uint8array:function(t){return l(t,new Uint8Array(t.length))},nodebuffer:function(t){return l(t,r.allocBuffer(t.length))}},c.array={string:f,array:n,arraybuffer:function(t){return new Uint8Array(t).buffer},uint8array:function(t){return new Uint8Array(t)},nodebuffer:function(t){return r.newBufferFrom(t)}},c.arraybuffer={string:function(t){return f(new Uint8Array(t))},array:function(t){return d(new Uint8Array(t),new Array(t.byteLength))},arraybuffer:n,uint8array:function(t){return new Uint8Array(t)},nodebuffer:function(t){return r.newBufferFrom(new Uint8Array(t))}},c.uint8array={string:f,array:function(t){return d(t,new Array(t.length))},arraybuffer:function(t){return t.buffer},uint8array:n,nodebuffer:function(t){return r.newBufferFrom(t)}},c.nodebuffer={string:f,array:function(t){return d(t,new Array(t.length))},arraybuffer:function(t){return c.nodebuffer.uint8array(t).buffer},uint8array:function(t){return d(t,new Uint8Array(t.length))},nodebuffer:n},a.transformTo=function(t,e){if(e=e||"",!t)return e;a.checkSupport(t);var r=a.getTypeOf(e);return c[r][t](e)},a.getTypeOf=function(t){return"string"==typeof t?"string":"[object Array]"===Object.prototype.toString.call(t)?"array":o.nodebuffer&&r.isBuffer(t)?"nodebuffer":o.uint8array&&t instanceof Uint8Array?"uint8array":o.arraybuffer&&t instanceof ArrayBuffer?"arraybuffer":void 0},a.checkSupport=function(t){if(!o[t.toLowerCase()])throw new Error(t+" is not supported by this platform")},a.MAX_VALUE_16BITS=65535,a.MAX_VALUE_32BITS=-1,a.pretty=function(t){var e,r,i="";for(r=0;r<(t||"").length;r++)i+="\\x"+((e=t.charCodeAt(r))<16?"0":"")+e.toString(16).toUpperCase();return i},a.delay=function(t,e,r){i(function(){t.apply(r||null,e||[])})},a.inherits=function(t,e){function r(){}r.prototype=e.prototype,t.prototype=new r},a.extend=function(){var t,e,r={};for(t=0;t<arguments.length;t++)for(e in arguments[t])arguments[t].hasOwnProperty(e)&&void 0===r[e]&&(r[e]=arguments[t][e]);return r},a.prepareContent=function(r,t,i,n,s){return u.Promise.resolve(t).then(function(i){return o.blob&&(i instanceof Blob||-1!==["[object File]","[object Blob]"].indexOf(Object.prototype.toString.call(i)))&&"undefined"!=typeof FileReader?new u.Promise(function(e,r){var t=new FileReader;t.onload=function(t){e(t.target.result)},t.onerror=function(t){r(t.target.error)},t.readAsArrayBuffer(i)}):i}).then(function(t){var e=a.getTypeOf(t);return e?("arraybuffer"===e?t=a.transformTo("uint8array",t):"string"===e&&(s?t=h.decode(t):i&&!0!==n&&(t=function(t){return l(t,o.uint8array?new Uint8Array(t.length):new Array(t.length))}(t))),t):u.Promise.reject(new Error("Can't read the data of '"+r+"'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?"))})}},{"./base64":1,"./external":6,"./nodejsUtils":14,"./support":30,"set-immediate-shim":54}],33:[function(t,e,r){"use strict";var i=t("./reader/readerFor"),n=t("./utils"),s=t("./signature"),a=t("./zipEntry"),o=(t("./utf8"),t("./support"));function h(t){this.files=[],this.loadOptions=t}h.prototype={checkSignature:function(t){if(!this.reader.readAndCheckSignature(t)){this.reader.index-=4;var e=this.reader.readString(4);throw new Error("Corrupted zip or bug: unexpected signature ("+n.pretty(e)+", expected "+n.pretty(t)+")")}},isSignature:function(t,e){var r=this.reader.index;this.reader.setIndex(t);var i=this.reader.readString(4)===e;return this.reader.setIndex(r),i},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2);var t=this.reader.readData(this.zipCommentLength),e=o.uint8array?"uint8array":"array",r=n.transformTo(e,t);this.zipComment=this.loadOptions.decodeFileName(r)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.reader.skip(4),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var t,e,r,i=this.zip64EndOfCentralSize-44;0<i;)t=this.reader.readInt(2),e=this.reader.readInt(4),r=this.reader.readData(e),this.zip64ExtensibleData[t]={id:t,length:e,value:r}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),1<this.disksCount)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var t,e;for(t=0;t<this.files.length;t++)e=this.files[t],this.reader.setIndex(e.localHeaderOffset),this.checkSignature(s.LOCAL_FILE_HEADER),e.readLocalPart(this.reader),e.handleUTF8(),e.processAttributes()},readCentralDir:function(){var t;for(this.reader.setIndex(this.centralDirOffset);this.reader.readAndCheckSignature(s.CENTRAL_FILE_HEADER);)(t=new a({zip64:this.zip64},this.loadOptions)).readCentralPart(this.reader),this.files.push(t);if(this.centralDirRecords!==this.files.length&&0!==this.centralDirRecords&&0===this.files.length)throw new Error("Corrupted zip or bug: expected "+this.centralDirRecords+" records in central dir, got "+this.files.length)},readEndOfCentral:function(){var t=this.reader.lastIndexOfSignature(s.CENTRAL_DIRECTORY_END);if(t<0)throw!this.isSignature(0,s.LOCAL_FILE_HEADER)?new Error("Can't find end of central directory : is this a zip file ? If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html"):new Error("Corrupted zip: can't find end of central directory");this.reader.setIndex(t);var e=t;if(this.checkSignature(s.CENTRAL_DIRECTORY_END),this.readBlockEndOfCentral(),this.diskNumber===n.MAX_VALUE_16BITS||this.diskWithCentralDirStart===n.MAX_VALUE_16BITS||this.centralDirRecordsOnThisDisk===n.MAX_VALUE_16BITS||this.centralDirRecords===n.MAX_VALUE_16BITS||this.centralDirSize===n.MAX_VALUE_32BITS||this.centralDirOffset===n.MAX_VALUE_32BITS){if(this.zip64=!0,(t=this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR))<0)throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");if(this.reader.setIndex(t),this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR),this.readBlockZip64EndOfCentralLocator(),!this.isSignature(this.relativeOffsetEndOfZip64CentralDir,s.ZIP64_CENTRAL_DIRECTORY_END)&&(this.relativeOffsetEndOfZip64CentralDir=this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_END),this.relativeOffsetEndOfZip64CentralDir<0))throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir),this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_END),this.readBlockZip64EndOfCentral()}var r=this.centralDirOffset+this.centralDirSize;this.zip64&&(r+=20,r+=12+this.zip64EndOfCentralSize);var i=e-r;if(0<i)this.isSignature(e,s.CENTRAL_FILE_HEADER)||(this.reader.zero=i);else if(i<0)throw new Error("Corrupted zip: missing "+Math.abs(i)+" bytes.")},prepareReader:function(t){this.reader=i(t)},load:function(t){this.prepareReader(t),this.readEndOfCentral(),this.readCentralDir(),this.readLocalFiles()}},e.exports=h},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utf8":31,"./utils":32,"./zipEntry":34}],34:[function(t,e,r){"use strict";var i=t("./reader/readerFor"),s=t("./utils"),n=t("./compressedObject"),a=t("./crc32"),o=t("./utf8"),h=t("./compressions"),u=t("./support");function l(t,e){this.options=t,this.loadOptions=e}l.prototype={isEncrypted:function(){return 1==(1&this.bitFlag)},useUTF8:function(){return 2048==(2048&this.bitFlag)},readLocalPart:function(t){var e,r;if(t.skip(22),this.fileNameLength=t.readInt(2),r=t.readInt(2),this.fileName=t.readData(this.fileNameLength),t.skip(r),-1===this.compressedSize||-1===this.uncompressedSize)throw new Error("Bug or corrupted zip : didn't get enough information from the central directory (compressedSize === -1 || uncompressedSize === -1)");if(null===(e=function(t){for(var e in h)if(h.hasOwnProperty(e)&&h[e].magic===t)return h[e];return null}(this.compressionMethod)))throw new Error("Corrupted zip : compression "+s.pretty(this.compressionMethod)+" unknown (inner file : "+s.transformTo("string",this.fileName)+")");this.decompressed=new n(this.compressedSize,this.uncompressedSize,this.crc32,e,t.readData(this.compressedSize))},readCentralPart:function(t){this.versionMadeBy=t.readInt(2),t.skip(2),this.bitFlag=t.readInt(2),this.compressionMethod=t.readString(2),this.date=t.readDate(),this.crc32=t.readInt(4),this.compressedSize=t.readInt(4),this.uncompressedSize=t.readInt(4);var e=t.readInt(2);if(this.extraFieldsLength=t.readInt(2),this.fileCommentLength=t.readInt(2),this.diskNumberStart=t.readInt(2),this.internalFileAttributes=t.readInt(2),this.externalFileAttributes=t.readInt(4),this.localHeaderOffset=t.readInt(4),this.isEncrypted())throw new Error("Encrypted zip are not supported");t.skip(e),this.readExtraFields(t),this.parseZIP64ExtraField(t),this.fileComment=t.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null,this.dosPermissions=null;var t=this.versionMadeBy>>8;this.dir=!!(16&this.externalFileAttributes),0==t&&(this.dosPermissions=63&this.externalFileAttributes),3==t&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(t){if(this.extraFields[1]){var e=i(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(t){var e,r,i,n=t.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});t.index+4<n;)e=t.readInt(2),r=t.readInt(2),i=t.readData(r),this.extraFields[e]={id:e,length:r,value:i};t.setIndex(n)},handleUTF8:function(){var t=u.uint8array?"uint8array":"array";if(this.useUTF8())this.fileNameStr=o.utf8decode(this.fileName),this.fileCommentStr=o.utf8decode(this.fileComment);else{var e=this.findExtraFieldUnicodePath();if(null!==e)this.fileNameStr=e;else{var r=s.transformTo(t,this.fileName);this.fileNameStr=this.loadOptions.decodeFileName(r)}var i=this.findExtraFieldUnicodeComment();if(null!==i)this.fileCommentStr=i;else{var n=s.transformTo(t,this.fileComment);this.fileCommentStr=this.loadOptions.decodeFileName(n)}}},findExtraFieldUnicodePath:function(){var t=this.extraFields[28789];if(t){var e=i(t.value);return 1!==e.readInt(1)?null:a(this.fileName)!==e.readInt(4)?null:o.utf8decode(e.readData(t.length-5))}return null},findExtraFieldUnicodeComment:function(){var t=this.extraFields[25461];if(t){var e=i(t.value);return 1!==e.readInt(1)?null:a(this.fileComment)!==e.readInt(4)?null:o.utf8decode(e.readData(t.length-5))}return null}},e.exports=l},{"./compressedObject":2,"./compressions":3,"./crc32":4,"./reader/readerFor":22,"./support":30,"./utf8":31,"./utils":32}],35:[function(t,e,r){"use strict";function i(t,e,r){this.name=t,this.dir=r.dir,this.date=r.date,this.comment=r.comment,this.unixPermissions=r.unixPermissions,this.dosPermissions=r.dosPermissions,this._data=e,this._dataBinary=r.binary,this.options={compression:r.compression,compressionOptions:r.compressionOptions}}var s=t("./stream/StreamHelper"),n=t("./stream/DataWorker"),a=t("./utf8"),o=t("./compressedObject"),h=t("./stream/GenericWorker");i.prototype={internalStream:function(t){var e=null,r="string";try{if(!t)throw new Error("No output type specified.");var i="string"===(r=t.toLowerCase())||"text"===r;"binarystring"!==r&&"text"!==r||(r="string"),e=this._decompressWorker();var n=!this._dataBinary;n&&!i&&(e=e.pipe(new a.Utf8EncodeWorker)),!n&&i&&(e=e.pipe(new a.Utf8DecodeWorker))}catch(t){(e=new h("error")).error(t)}return new s(e,r,"")},async:function(t,e){return this.internalStream(t).accumulate(e)},nodeStream:function(t,e){return this.internalStream(t||"nodebuffer").toNodejsStream(e)},_compressWorker:function(t,e){if(this._data instanceof o&&this._data.compression.magic===t.magic)return this._data.getCompressedWorker();var r=this._decompressWorker();return this._dataBinary||(r=r.pipe(new a.Utf8EncodeWorker)),o.createWorkerFrom(r,t,e)},_decompressWorker:function(){return this._data instanceof o?this._data.getContentWorker():this._data instanceof h?this._data:new n(this._data)}};for(var u=["asText","asBinary","asNodeBuffer","asUint8Array","asArrayBuffer"],l=function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},f=0;f<u.length;f++)i.prototype[u[f]]=l;e.exports=i},{"./compressedObject":2,"./stream/DataWorker":27,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31}],36:[function(t,l,e){(function(e){"use strict";var r,i,t=e.MutationObserver||e.WebKitMutationObserver;if(t){var n=0,s=new t(u),a=e.document.createTextNode("");s.observe(a,{characterData:!0}),r=function(){a.data=n=++n%2}}else if(e.setImmediate||void 0===e.MessageChannel)r="document"in e&&"onreadystatechange"in e.document.createElement("script")?function(){var t=e.document.createElement("script");t.onreadystatechange=function(){u(),t.onreadystatechange=null,t.parentNode.removeChild(t),t=null},e.document.documentElement.appendChild(t)}:function(){setTimeout(u,0)};else{var o=new e.MessageChannel;o.port1.onmessage=u,r=function(){o.port2.postMessage(0)}}var h=[];function u(){var t,e;i=!0;for(var r=h.length;r;){for(e=h,h=[],t=-1;++t<r;)e[t]();r=h.length}i=!1}l.exports=function(t){1!==h.push(t)||i||r()}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],37:[function(t,e,r){"use strict";var n=t("immediate");function u(){}var l={},s=["REJECTED"],a=["FULFILLED"],i=["PENDING"];function o(t){if("function"!=typeof t)throw new TypeError("resolver must be a function");this.state=i,this.queue=[],this.outcome=void 0,t!==u&&c(this,t)}function h(t,e,r){this.promise=t,"function"==typeof e&&(this.onFulfilled=e,this.callFulfilled=this.otherCallFulfilled),"function"==typeof r&&(this.onRejected=r,this.callRejected=this.otherCallRejected)}function f(e,r,i){n(function(){var t;try{t=r(i)}catch(t){return l.reject(e,t)}t===e?l.reject(e,new TypeError("Cannot resolve promise with itself")):l.resolve(e,t)})}function d(t){var e=t&&t.then;if(t&&("object"==typeof t||"function"==typeof t)&&"function"==typeof e)return function(){e.apply(t,arguments)}}function c(e,t){var r=!1;function i(t){r||(r=!0,l.reject(e,t))}function n(t){r||(r=!0,l.resolve(e,t))}var s=p(function(){t(n,i)});"error"===s.status&&i(s.value)}function p(t,e){var r={};try{r.value=t(e),r.status="success"}catch(t){r.status="error",r.value=t}return r}(e.exports=o).prototype.finally=function(e){if("function"!=typeof e)return this;var r=this.constructor;return this.then(function(t){return r.resolve(e()).then(function(){return t})},function(t){return r.resolve(e()).then(function(){throw t})})},o.prototype.catch=function(t){return this.then(null,t)},o.prototype.then=function(t,e){if("function"!=typeof t&&this.state===a||"function"!=typeof e&&this.state===s)return this;var r=new this.constructor(u);this.state!==i?f(r,this.state===a?t:e,this.outcome):this.queue.push(new h(r,t,e));return r},h.prototype.callFulfilled=function(t){l.resolve(this.promise,t)},h.prototype.otherCallFulfilled=function(t){f(this.promise,this.onFulfilled,t)},h.prototype.callRejected=function(t){l.reject(this.promise,t)},h.prototype.otherCallRejected=function(t){f(this.promise,this.onRejected,t)},l.resolve=function(t,e){var r=p(d,e);if("error"===r.status)return l.reject(t,r.value);var i=r.value;if(i)c(t,i);else{t.state=a,t.outcome=e;for(var n=-1,s=t.queue.length;++n<s;)t.queue[n].callFulfilled(e)}return t},l.reject=function(t,e){t.state=s,t.outcome=e;for(var r=-1,i=t.queue.length;++r<i;)t.queue[r].callRejected(e);return t},o.resolve=function(t){if(t instanceof this)return t;return l.resolve(new this(u),t)},o.reject=function(t){var e=new this(u);return l.reject(e,t)},o.all=function(t){var r=this;if("[object Array]"!==Object.prototype.toString.call(t))return this.reject(new TypeError("must be an array"));var i=t.length,n=!1;if(!i)return this.resolve([]);var s=new Array(i),a=0,e=-1,o=new this(u);for(;++e<i;)h(t[e],e);return o;function h(t,e){r.resolve(t).then(function(t){s[e]=t,++a!==i||n||(n=!0,l.resolve(o,s))},function(t){n||(n=!0,l.reject(o,t))})}},o.race=function(t){var e=this;if("[object Array]"!==Object.prototype.toString.call(t))return this.reject(new TypeError("must be an array"));var r=t.length,i=!1;if(!r)return this.resolve([]);var n=-1,s=new this(u);for(;++n<r;)a=t[n],e.resolve(a).then(function(t){i||(i=!0,l.resolve(s,t))},function(t){i||(i=!0,l.reject(s,t))});var a;return s}},{immediate:36}],38:[function(t,e,r){"use strict";var i={};(0,t("./lib/utils/common").assign)(i,t("./lib/deflate"),t("./lib/inflate"),t("./lib/zlib/constants")),e.exports=i},{"./lib/deflate":39,"./lib/inflate":40,"./lib/utils/common":41,"./lib/zlib/constants":44}],39:[function(t,e,r){"use strict";var a=t("./zlib/deflate"),o=t("./utils/common"),h=t("./utils/strings"),n=t("./zlib/messages"),s=t("./zlib/zstream"),u=Object.prototype.toString,l=0,f=-1,d=0,c=8;function p(t){if(!(this instanceof p))return new p(t);this.options=o.assign({level:f,method:c,chunkSize:16384,windowBits:15,memLevel:8,strategy:d,to:""},t||{});var e=this.options;e.raw&&0<e.windowBits?e.windowBits=-e.windowBits:e.gzip&&0<e.windowBits&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new s,this.strm.avail_out=0;var r=a.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(r!==l)throw new Error(n[r]);if(e.header&&a.deflateSetHeader(this.strm,e.header),e.dictionary){var i;if(i="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===u.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,(r=a.deflateSetDictionary(this.strm,i))!==l)throw new Error(n[r]);this._dict_set=!0}}function i(t,e){var r=new p(e);if(r.push(t,!0),r.err)throw r.msg||n[r.err];return r.result}p.prototype.push=function(t,e){var r,i,n=this.strm,s=this.options.chunkSize;if(this.ended)return!1;i=e===~~e?e:!0===e?4:0,"string"==typeof t?n.input=h.string2buf(t):"[object ArrayBuffer]"===u.call(t)?n.input=new Uint8Array(t):n.input=t,n.next_in=0,n.avail_in=n.input.length;do{if(0===n.avail_out&&(n.output=new o.Buf8(s),n.next_out=0,n.avail_out=s),1!==(r=a.deflate(n,i))&&r!==l)return this.onEnd(r),!(this.ended=!0);0!==n.avail_out&&(0!==n.avail_in||4!==i&&2!==i)||("string"===this.options.to?this.onData(h.buf2binstring(o.shrinkBuf(n.output,n.next_out))):this.onData(o.shrinkBuf(n.output,n.next_out)))}while((0<n.avail_in||0===n.avail_out)&&1!==r);return 4===i?(r=a.deflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===l):2!==i||(this.onEnd(l),!(n.avail_out=0))},p.prototype.onData=function(t){this.chunks.push(t)},p.prototype.onEnd=function(t){t===l&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},r.Deflate=p,r.deflate=i,r.deflateRaw=function(t,e){return(e=e||{}).raw=!0,i(t,e)},r.gzip=function(t,e){return(e=e||{}).gzip=!0,i(t,e)}},{"./utils/common":41,"./utils/strings":42,"./zlib/deflate":46,"./zlib/messages":51,"./zlib/zstream":53}],40:[function(t,e,r){"use strict";var d=t("./zlib/inflate"),c=t("./utils/common"),p=t("./utils/strings"),m=t("./zlib/constants"),i=t("./zlib/messages"),n=t("./zlib/zstream"),s=t("./zlib/gzheader"),_=Object.prototype.toString;function a(t){if(!(this instanceof a))return new a(t);this.options=c.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&0<=e.windowBits&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(0<=e.windowBits&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),15<e.windowBits&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new n,this.strm.avail_out=0;var r=d.inflateInit2(this.strm,e.windowBits);if(r!==m.Z_OK)throw new Error(i[r]);this.header=new s,d.inflateGetHeader(this.strm,this.header)}function o(t,e){var r=new a(e);if(r.push(t,!0),r.err)throw r.msg||i[r.err];return r.result}a.prototype.push=function(t,e){var r,i,n,s,a,o,h=this.strm,u=this.options.chunkSize,l=this.options.dictionary,f=!1;if(this.ended)return!1;i=e===~~e?e:!0===e?m.Z_FINISH:m.Z_NO_FLUSH,"string"==typeof t?h.input=p.binstring2buf(t):"[object ArrayBuffer]"===_.call(t)?h.input=new Uint8Array(t):h.input=t,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new c.Buf8(u),h.next_out=0,h.avail_out=u),(r=d.inflate(h,m.Z_NO_FLUSH))===m.Z_NEED_DICT&&l&&(o="string"==typeof l?p.string2buf(l):"[object ArrayBuffer]"===_.call(l)?new Uint8Array(l):l,r=d.inflateSetDictionary(this.strm,o)),r===m.Z_BUF_ERROR&&!0===f&&(r=m.Z_OK,f=!1),r!==m.Z_STREAM_END&&r!==m.Z_OK)return this.onEnd(r),!(this.ended=!0);h.next_out&&(0!==h.avail_out&&r!==m.Z_STREAM_END&&(0!==h.avail_in||i!==m.Z_FINISH&&i!==m.Z_SYNC_FLUSH)||("string"===this.options.to?(n=p.utf8border(h.output,h.next_out),s=h.next_out-n,a=p.buf2string(h.output,n),h.next_out=s,h.avail_out=u-s,s&&c.arraySet(h.output,h.output,n,s,0),this.onData(a)):this.onData(c.shrinkBuf(h.output,h.next_out)))),0===h.avail_in&&0===h.avail_out&&(f=!0)}while((0<h.avail_in||0===h.avail_out)&&r!==m.Z_STREAM_END);return r===m.Z_STREAM_END&&(i=m.Z_FINISH),i===m.Z_FINISH?(r=d.inflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===m.Z_OK):i!==m.Z_SYNC_FLUSH||(this.onEnd(m.Z_OK),!(h.avail_out=0))},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===m.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=c.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},r.Inflate=a,r.inflate=o,r.inflateRaw=function(t,e){return(e=e||{}).raw=!0,o(t,e)},r.ungzip=o},{"./utils/common":41,"./utils/strings":42,"./zlib/constants":44,"./zlib/gzheader":47,"./zlib/inflate":49,"./zlib/messages":51,"./zlib/zstream":53}],41:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;r.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var r=e.shift();if(r){if("object"!=typeof r)throw new TypeError(r+"must be non-object");for(var i in r)r.hasOwnProperty(i)&&(t[i]=r[i])}}return t},r.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var n={arraySet:function(t,e,r,i,n){if(e.subarray&&t.subarray)t.set(e.subarray(r,r+i),n);else for(var s=0;s<i;s++)t[n+s]=e[r+s]},flattenChunks:function(t){var e,r,i,n,s,a;for(e=i=0,r=t.length;e<r;e++)i+=t[e].length;for(a=new Uint8Array(i),e=n=0,r=t.length;e<r;e++)s=t[e],a.set(s,n),n+=s.length;return a}},s={arraySet:function(t,e,r,i,n){for(var s=0;s<i;s++)t[n+s]=e[r+s]},flattenChunks:function(t){return[].concat.apply([],t)}};r.setTyped=function(t){t?(r.Buf8=Uint8Array,r.Buf16=Uint16Array,r.Buf32=Int32Array,r.assign(r,n)):(r.Buf8=Array,r.Buf16=Array,r.Buf32=Array,r.assign(r,s))},r.setTyped(i)},{}],42:[function(t,e,r){"use strict";var h=t("./common"),n=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){n=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var u=new h.Buf8(256),i=0;i<256;i++)u[i]=252<=i?6:248<=i?5:240<=i?4:224<=i?3:192<=i?2:1;function l(t,e){if(e<65537&&(t.subarray&&s||!t.subarray&&n))return String.fromCharCode.apply(null,h.shrinkBuf(t,e));for(var r="",i=0;i<e;i++)r+=String.fromCharCode(t[i]);return r}u[254]=u[254]=1,r.string2buf=function(t){var e,r,i,n,s,a=t.length,o=0;for(n=0;n<a;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),o+=r<128?1:r<2048?2:r<65536?3:4;for(e=new h.Buf8(o),n=s=0;s<o;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),r<128?e[s++]=r:(r<2048?e[s++]=192|r>>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e},r.buf2binstring=function(t){return l(t,t.length)},r.binstring2buf=function(t){for(var e=new h.Buf8(t.length),r=0,i=e.length;r<i;r++)e[r]=t.charCodeAt(r);return e},r.buf2string=function(t,e){var r,i,n,s,a=e||t.length,o=new Array(2*a);for(r=i=0;r<a;)if((n=t[r++])<128)o[i++]=n;else if(4<(s=u[n]))o[i++]=65533,r+=s-1;else{for(n&=2===s?31:3===s?15:7;1<s&&r<a;)n=n<<6|63&t[r++],s--;1<s?o[i++]=65533:n<65536?o[i++]=n:(n-=65536,o[i++]=55296|n>>10&1023,o[i++]=56320|1023&n)}return l(o,i)},r.utf8border=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}},{"./common":41}],43:[function(t,e,r){"use strict";e.exports=function(t,e,r,i){for(var n=65535&t|0,s=t>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3<r?2e3:r;s=s+(n=n+e[i++]|0)|0,--a;);n%=65521,s%=65521}return n|s<<16|0}},{}],44:[function(t,e,r){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],45:[function(t,e,r){"use strict";var o=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e[a])];return-1^t}},{}],46:[function(t,e,r){"use strict";var h,d=t("../utils/common"),u=t("./trees"),c=t("./adler32"),p=t("./crc32"),i=t("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,n=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(t,e){return t.msg=i[e],e}function T(t){return(t<<1)-(4<t?9:0)}function D(t){for(var e=t.length;0<=--e;)t[e]=0}function F(t){var e=t.state,r=e.pending;r>t.avail_out&&(r=t.avail_out),0!==r&&(d.arraySet(t.output,e.pending_buf,e.pending_out,r,t.next_out),t.next_out+=r,e.pending_out+=r,t.total_out+=r,t.avail_out-=r,e.pending-=r,0===e.pending&&(e.pending_out=0))}function N(t,e){u._tr_flush_block(t,0<=t.block_start?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,F(t.strm)}function U(t,e){t.pending_buf[t.pending++]=e}function P(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function L(t,e){var r,i,n=t.max_chain_length,s=t.strstart,a=t.prev_length,o=t.nice_match,h=t.strstart>t.w_size-z?t.strstart-(t.w_size-z):0,u=t.window,l=t.w_mask,f=t.prev,d=t.strstart+S,c=u[s+a-1],p=u[s+a];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(u[(r=e)+a]===p&&u[r+a-1]===c&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&s<d);if(i=S-(d-s),s=d-S,a<i){if(t.match_start=e,o<=(a=i))break;c=u[s+a-1],p=u[s+a]}}}while((e=f[e&l])>h&&0!=--n);return a<=t.lookahead?a:t.lookahead}function j(t){var e,r,i,n,s,a,o,h,u,l,f=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=f+(f-z)){for(d.arraySet(t.window,t.window,f,f,0),t.match_start-=f,t.strstart-=f,t.block_start-=f,e=r=t.hash_size;i=t.head[--e],t.head[e]=f<=i?i-f:0,--r;);for(e=r=f;i=t.prev[--e],t.prev[e]=f<=i?i-f:0,--r;);n+=f}if(0===t.strm.avail_in)break;if(a=t.strm,o=t.window,h=t.strstart+t.lookahead,u=n,l=void 0,l=a.avail_in,u<l&&(l=u),r=0===l?0:(a.avail_in-=l,d.arraySet(o,a.input,a.next_in,l,h),1===a.state.wrap?a.adler=c(a.adler,o,l,h):2===a.state.wrap&&(a.adler=p(a.adler,o,l,h)),a.next_in+=l,a.total_in+=l,l),t.lookahead+=r,t.lookahead+t.insert>=x)for(s=t.strstart-t.insert,t.ins_h=t.window[s],t.ins_h=(t.ins_h<<t.hash_shift^t.window[s+1])&t.hash_mask;t.insert&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[s+x-1])&t.hash_mask,t.prev[s&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=s,s++,t.insert--,!(t.lookahead+t.insert<x)););}while(t.lookahead<z&&0!==t.strm.avail_in)}function Z(t,e){for(var r,i;;){if(t.lookahead<z){if(j(t),t.lookahead<z&&e===l)return A;if(0===t.lookahead)break}if(r=0,t.lookahead>=x&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==r&&t.strstart-r<=t.w_size-z&&(t.match_length=L(t,r)),t.match_length>=x)if(i=u._tr_tally(t,t.strstart-t.match_start,t.match_length-x),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=x){for(t.match_length--;t.strstart++,t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart,0!=--t.match_length;);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+1])&t.hash_mask;else i=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(i&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=t.strstart<x-1?t.strstart:x-1,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}function W(t,e){for(var r,i,n;;){if(t.lookahead<z){if(j(t),t.lookahead<z&&e===l)return A;if(0===t.lookahead)break}if(r=0,t.lookahead>=x&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=x-1,0!==r&&t.prev_length<t.max_lazy_match&&t.strstart-r<=t.w_size-z&&(t.match_length=L(t,r),t.match_length<=5&&(1===t.strategy||t.match_length===x&&4096<t.strstart-t.match_start)&&(t.match_length=x-1)),t.prev_length>=x&&t.match_length<=t.prev_length){for(n=t.strstart+t.lookahead-x,i=u._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-x),t.lookahead-=t.prev_length-1,t.prev_length-=2;++t.strstart<=n&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!=--t.prev_length;);if(t.match_available=0,t.match_length=x-1,t.strstart++,i&&(N(t,!1),0===t.strm.avail_out))return A}else if(t.match_available){if((i=u._tr_tally(t,0,t.window[t.strstart-1]))&&N(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return A}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(i=u._tr_tally(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<x-1?t.strstart:x-1,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}function M(t,e,r,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=r,this.max_chain=i,this.func=n}function H(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=v,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new d.Buf16(2*w),this.dyn_dtree=new d.Buf16(2*(2*a+1)),this.bl_tree=new d.Buf16(2*(2*o+1)),D(this.dyn_ltree),D(this.dyn_dtree),D(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new d.Buf16(k+1),this.heap=new d.Buf16(2*s+1),D(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new d.Buf16(2*s+1),D(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function G(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=n,(e=t.state).pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?C:E,t.adler=2===e.wrap?0:1,e.last_flush=l,u._tr_init(e),m):R(t,_)}function K(t){var e=G(t);return e===m&&function(t){t.window_size=2*t.w_size,D(t.head),t.max_lazy_match=h[t.level].max_lazy,t.good_match=h[t.level].good_length,t.nice_match=h[t.level].nice_length,t.max_chain_length=h[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=x-1,t.match_available=0,t.ins_h=0}(t.state),e}function Y(t,e,r,i,n,s){if(!t)return _;var a=1;if(e===g&&(e=6),i<0?(a=0,i=-i):15<i&&(a=2,i-=16),n<1||y<n||r!==v||i<8||15<i||e<0||9<e||s<0||b<s)return R(t,_);8===i&&(i=9);var o=new H;return(t.state=o).strm=t,o.wrap=a,o.gzhead=null,o.w_bits=i,o.w_size=1<<o.w_bits,o.w_mask=o.w_size-1,o.hash_bits=n+7,o.hash_size=1<<o.hash_bits,o.hash_mask=o.hash_size-1,o.hash_shift=~~((o.hash_bits+x-1)/x),o.window=new d.Buf8(2*o.w_size),o.head=new d.Buf16(o.hash_size),o.prev=new d.Buf16(o.w_size),o.lit_bufsize=1<<n+6,o.pending_buf_size=4*o.lit_bufsize,o.pending_buf=new d.Buf8(o.pending_buf_size),o.d_buf=1*o.lit_bufsize,o.l_buf=3*o.lit_bufsize,o.level=e,o.strategy=s,o.method=r,K(t)}h=[new M(0,0,0,0,function(t,e){var r=65535;for(r>t.pending_buf_size-5&&(r=t.pending_buf_size-5);;){if(t.lookahead<=1){if(j(t),0===t.lookahead&&e===l)return A;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+r;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,N(t,!1),0===t.strm.avail_out))return A;if(t.strstart-t.block_start>=t.w_size-z&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):(t.strstart>t.block_start&&(N(t,!1),t.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(t,e){return Y(t,e,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(t,e){return t&&t.state?2!==t.state.wrap?_:(t.state.gzhead=e,m):_},r.deflate=function(t,e){var r,i,n,s;if(!t||!t.state||5<e||e<0)return t?R(t,_):_;if(i=t.state,!t.output||!t.input&&0!==t.avail_in||666===i.status&&e!==f)return R(t,0===t.avail_out?-5:_);if(i.strm=t,r=i.last_flush,i.last_flush=e,i.status===C)if(2===i.wrap)t.adler=0,U(i,31),U(i,139),U(i,8),i.gzhead?(U(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(i.gzhead.extra?4:0)+(i.gzhead.name?8:0)+(i.gzhead.comment?16:0)),U(i,255&i.gzhead.time),U(i,i.gzhead.time>>8&255),U(i,i.gzhead.time>>16&255),U(i,i.gzhead.time>>24&255),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(U(i,255&i.gzhead.extra.length),U(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=p(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69):(U(i,0),U(i,0),U(i,0),U(i,0),U(i,0),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,3),i.status=E);else{var a=v+(i.w_bits-8<<4)<<8;a|=(2<=i.strategy||i.level<2?0:i.level<6?1:6===i.level?2:3)<<6,0!==i.strstart&&(a|=32),a+=31-a%31,i.status=E,P(i,a),0!==i.strstart&&(P(i,t.adler>>>16),P(i,65535&t.adler)),t.adler=1}if(69===i.status)if(i.gzhead.extra){for(n=i.pending;i.gzindex<(65535&i.gzhead.extra.length)&&(i.pending!==i.pending_buf_size||(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending!==i.pending_buf_size));)U(i,255&i.gzhead.extra[i.gzindex]),i.gzindex++;i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),i.gzindex===i.gzhead.extra.length&&(i.gzindex=0,i.status=73)}else i.status=73;if(73===i.status)if(i.gzhead.name){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindex<i.gzhead.name.length?255&i.gzhead.name.charCodeAt(i.gzindex++):0,U(i,s)}while(0!==s);i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.gzindex=0,i.status=91)}else i.status=91;if(91===i.status)if(i.gzhead.comment){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindex<i.gzhead.comment.length?255&i.gzhead.comment.charCodeAt(i.gzindex++):0,U(i,s)}while(0!==s);i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.status=103)}else i.status=103;if(103===i.status&&(i.gzhead.hcrc?(i.pending+2>i.pending_buf_size&&F(t),i.pending+2<=i.pending_buf_size&&(U(i,255&t.adler),U(i,t.adler>>8&255),t.adler=0,i.status=E)):i.status=E),0!==i.pending){if(F(t),0===t.avail_out)return i.last_flush=-1,m}else if(0===t.avail_in&&T(e)<=T(r)&&e!==f)return R(t,-5);if(666===i.status&&0!==t.avail_in)return R(t,-5);if(0!==t.avail_in||0!==i.lookahead||e!==l&&666!==i.status){var o=2===i.strategy?function(t,e){for(var r;;){if(0===t.lookahead&&(j(t),0===t.lookahead)){if(e===l)return A;break}if(t.match_length=0,r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):3===i.strategy?function(t,e){for(var r,i,n,s,a=t.window;;){if(t.lookahead<=S){if(j(t),t.lookahead<=S&&e===l)return A;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=x&&0<t.strstart&&(i=a[n=t.strstart-1])===a[++n]&&i===a[++n]&&i===a[++n]){s=t.strstart+S;do{}while(i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&n<s);t.match_length=S-(s-n),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=x?(r=u._tr_tally(t,1,t.match_length-x),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):h[i.level].func(i,e);if(o!==O&&o!==B||(i.status=666),o===A||o===O)return 0===t.avail_out&&(i.last_flush=-1),m;if(o===I&&(1===e?u._tr_align(i):5!==e&&(u._tr_stored_block(i,0,0,!1),3===e&&(D(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),F(t),0===t.avail_out))return i.last_flush=-1,m}return e!==f?m:i.wrap<=0?1:(2===i.wrap?(U(i,255&t.adler),U(i,t.adler>>8&255),U(i,t.adler>>16&255),U(i,t.adler>>24&255),U(i,255&t.total_in),U(i,t.total_in>>8&255),U(i,t.total_in>>16&255),U(i,t.total_in>>24&255)):(P(i,t.adler>>>16),P(i,65535&t.adler)),F(t),0<i.wrap&&(i.wrap=-i.wrap),0!==i.pending?m:1)},r.deflateEnd=function(t){var e;return t&&t.state?(e=t.state.status)!==C&&69!==e&&73!==e&&91!==e&&103!==e&&e!==E&&666!==e?R(t,_):(t.state=null,e===E?R(t,-3):m):_},r.deflateSetDictionary=function(t,e){var r,i,n,s,a,o,h,u,l=e.length;if(!t||!t.state)return _;if(2===(s=(r=t.state).wrap)||1===s&&r.status!==C||r.lookahead)return _;for(1===s&&(t.adler=c(t.adler,e,l,0)),r.wrap=0,l>=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new d.Buf8(r.w_size),d.arraySet(u,e,l-r.w_size,r.w_size,0),e=u,l=r.w_size),a=t.avail_in,o=t.next_in,h=t.input,t.avail_in=l,t.next_in=0,t.input=e,j(r);r.lookahead>=x;){for(i=r.strstart,n=r.lookahead-(x-1);r.ins_h=(r.ins_h<<r.hash_shift^r.window[i+x-1])&r.hash_mask,r.prev[i&r.w_mask]=r.head[r.ins_h],r.head[r.ins_h]=i,i++,--n;);r.strstart=i,r.lookahead=x-1,j(r)}return r.strstart+=r.lookahead,r.block_start=r.strstart,r.insert=r.lookahead,r.lookahead=0,r.match_length=r.prev_length=x-1,r.match_available=0,t.next_in=o,t.input=h,t.avail_in=a,r.wrap=s,m},r.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./messages":51,"./trees":52}],47:[function(t,e,r){"use strict";e.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],48:[function(t,e,r){"use strict";e.exports=function(t,e){var r,i,n,s,a,o,h,u,l,f,d,c,p,m,_,g,b,v,y,w,k,x,S,z,C;r=t.state,i=t.next_in,z=t.input,n=i+(t.avail_in-5),s=t.next_out,C=t.output,a=s-(e-t.avail_out),o=s+(t.avail_out-257),h=r.dmax,u=r.wsize,l=r.whave,f=r.wnext,d=r.window,c=r.hold,p=r.bits,m=r.lencode,_=r.distcode,g=(1<<r.lenbits)-1,b=(1<<r.distbits)-1;t:do{p<15&&(c+=z[i++]<<p,p+=8,c+=z[i++]<<p,p+=8),v=m[c&g];e:for(;;){if(c>>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(c&(1<<y)-1)];continue e}if(32&y){r.mode=12;break t}t.msg="invalid literal/length code",r.mode=30;break t}w=65535&v,(y&=15)&&(p<y&&(c+=z[i++]<<p,p+=8),w+=c&(1<<y)-1,c>>>=y,p-=y),p<15&&(c+=z[i++]<<p,p+=8,c+=z[i++]<<p,p+=8),v=_[c&b];r:for(;;){if(c>>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(c&(1<<y)-1)];continue r}t.msg="invalid distance code",r.mode=30;break t}if(k=65535&v,p<(y&=15)&&(c+=z[i++]<<p,(p+=8)<y&&(c+=z[i++]<<p,p+=8)),h<(k+=c&(1<<y)-1)){t.msg="invalid distance too far back",r.mode=30;break t}if(c>>>=y,p-=y,(y=s-a)<k){if(l<(y=k-y)&&r.sane){t.msg="invalid distance too far back",r.mode=30;break t}if(S=d,(x=0)===f){if(x+=u-y,y<w){for(w-=y;C[s++]=d[x++],--y;);x=s-k,S=C}}else if(f<y){if(x+=u+f-y,(y-=f)<w){for(w-=y;C[s++]=d[x++],--y;);if(x=0,f<w){for(w-=y=f;C[s++]=d[x++],--y;);x=s-k,S=C}}}else if(x+=f-y,y<w){for(w-=y;C[s++]=d[x++],--y;);x=s-k,S=C}for(;2<w;)C[s++]=S[x++],C[s++]=S[x++],C[s++]=S[x++],w-=3;w&&(C[s++]=S[x++],1<w&&(C[s++]=S[x++]))}else{for(x=s-k;C[s++]=C[x++],C[s++]=C[x++],C[s++]=C[x++],2<(w-=3););w&&(C[s++]=C[x++],1<w&&(C[s++]=C[x++]))}break}}break}}while(i<n&&s<o);i-=w=p>>3,c&=(1<<(p-=w<<3))-1,t.next_in=i,t.next_out=s,t.avail_in=i<n?n-i+5:5-(i-n),t.avail_out=s<o?o-s+257:257-(s-o),r.hold=c,r.bits=p}},{}],49:[function(t,e,r){"use strict";var I=t("../utils/common"),O=t("./adler32"),B=t("./crc32"),R=t("./inffast"),T=t("./inftrees"),D=1,F=2,N=0,U=-2,P=1,i=852,n=592;function L(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=P,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new I.Buf32(i),e.distcode=e.distdyn=new I.Buf32(n),e.sane=1,e.back=-1,N):U}function o(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,a(t)):U}function h(t,e){var r,i;return t&&t.state?(i=t.state,e<0?(r=0,e=-e):(r=1+(e>>4),e<48&&(e&=15)),e&&(e<8||15<e)?U:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=r,i.wbits=e,o(t))):U}function u(t,e){var r,i;return t?(i=new s,(t.state=i).window=null,(r=h(t,e))!==N&&(t.state=null),r):U}var l,f,d=!0;function j(t){if(d){var e;for(l=new I.Buf32(512),f=new I.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(T(D,t.lens,0,288,l,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;T(F,t.lens,0,32,f,0,t.work,{bits:5}),d=!1}t.lencode=l,t.lenbits=9,t.distcode=f,t.distbits=5}function Z(t,e,r,i){var n,s=t.state;return null===s.window&&(s.wsize=1<<s.wbits,s.wnext=0,s.whave=0,s.window=new I.Buf8(s.wsize)),i>=s.wsize?(I.arraySet(s.window,e,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(i<(n=s.wsize-s.wnext)&&(n=i),I.arraySet(s.window,e,r-i,n,s.wnext),(i-=n)?(I.arraySet(s.window,e,r-i,i,0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave<s.wsize&&(s.whave+=n))),0}r.inflateReset=o,r.inflateReset2=h,r.inflateResetKeep=a,r.inflateInit=function(t){return u(t,15)},r.inflateInit2=u,r.inflate=function(t,e){var r,i,n,s,a,o,h,u,l,f,d,c,p,m,_,g,b,v,y,w,k,x,S,z,C=0,E=new I.Buf8(4),A=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return U;12===(r=t.state).mode&&(r.mode=13),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,f=o,d=h,x=N;t:for(;;)switch(r.mode){case P:if(0===r.wrap){r.mode=13;break}for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(2&r.wrap&&35615===u){E[r.check=0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){t.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){t.msg="invalid window size",r.mode=30;break}r.dmax=1<<k,t.adler=r.check=1,r.mode=512&u?10:12,l=u=0;break;case 2:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(r.flags=u,8!=(255&r.flags)){t.msg="unknown compression method",r.mode=30;break}if(57344&r.flags){t.msg="unknown header flags set",r.mode=30;break}r.head&&(r.head.text=u>>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.head&&(r.head.time=u),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.head&&(r.head.xflags=255&u,r.head.os=u>>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.length=u,r.head&&(r.head.extra_len=u),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,i,s,c,k)),512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,r.length-=c),r.length))break t;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c<o;);if(512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,k)break t}else r.head&&(r.head.name=null);r.length=0,r.mode=8;case 8:if(4096&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.comment+=String.fromCharCode(k)),k&&c<o;);if(512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,k)break t}else r.head&&(r.head.comment=null);r.mode=9;case 9:if(512&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u!==(65535&r.check)){t.msg="header crc mismatch",r.mode=30;break}l=u=0}r.head&&(r.head.hcrc=r.flags>>9&1,r.head.done=!0),t.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}t.adler=r.check=L(u),l=u=0,r.mode=11;case 11:if(0===r.havedict)return t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,2;t.adler=r.check=1,r.mode=12;case 12:if(5===e||6===e)break t;case 13:if(r.last){u>>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}switch(r.last=1&u,l-=1,3&(u>>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==e)break;u>>>=2,l-=2;break t;case 2:r.mode=17;break;case 3:t.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if((65535&u)!=(u>>>16^65535)){t.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===e)break t;case 15:r.mode=16;case 16:if(c=r.length){if(o<c&&(c=o),h<c&&(c=h),0===c)break t;I.arraySet(n,i,s,c,a),o-=c,s+=c,h-=c,a+=c,r.length-=c;break}r.mode=12;break;case 17:for(;l<14;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(r.nlen=257+(31&u),u>>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286<r.nlen||30<r.ndist){t.msg="too many length or distance symbols",r.mode=30;break}r.have=0,r.mode=18;case 18:for(;r.have<r.ncode;){for(;l<3;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.lens[A[r.have++]]=7&u,u>>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have<r.nlen+r.ndist;){for(;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(b<16)u>>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u>>>=_,l-=_,0===r.have){t.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}l-=_,k=0,c=3+(7&(u>>>=_)),u>>>=3,l-=3}else{for(z=_+7;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}l-=_,k=0,c=11+(127&(u>>>=_)),u>>>=7,l-=7}if(r.have+c>r.nlen+r.ndist){t.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){t.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){t.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===e)break t;case 20:r.mode=21;case 21:if(6<=o&&258<=h){t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,R(t,d),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(g&&0==(240&g)){for(v=_,y=g,w=b;g=(C=r.lencode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){t.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.length+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<<r.distbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(0==(240&g)){for(v=_,y=g,w=b;g=(C=r.distcode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){t.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.offset+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){t.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break t;if(c=d-h,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){t.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=n,p=a-r.offset,c=r.length;for(h<c&&(c=h),h-=c,r.length-=c;n[a++]=m[p++],--c;);0===r.length&&(r.mode=21);break;case 26:if(0===h)break t;n[a++]=r.length,h--,r.mode=21;break;case 27:if(r.wrap){for(;l<32;){if(0===o)break t;o--,u|=i[s++]<<l,l+=8}if(d-=h,t.total_out+=d,r.total+=d,d&&(t.adler=r.check=r.flags?B(r.check,n,d,a-d):O(r.check,n,d,a-d)),d=h,(r.flags?u:L(u))!==r.check){t.msg="incorrect data check",r.mode=30;break}l=u=0}r.mode=28;case 28:if(r.wrap&&r.flags){for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u!==(4294967295&r.total)){t.msg="incorrect length check",r.mode=30;break}l=u=0}r.mode=29;case 29:x=1;break t;case 30:x=-3;break t;case 31:return-4;case 32:default:return U}return t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,(r.wsize||d!==t.avail_out&&r.mode<30&&(r.mode<27||4!==e))&&Z(t,t.output,t.next_out,d-t.avail_out)?(r.mode=31,-4):(f-=t.avail_in,d-=t.avail_out,t.total_in+=f,t.total_out+=d,r.total+=d,r.wrap&&d&&(t.adler=r.check=r.flags?B(r.check,n,d,t.next_out-d):O(r.check,n,d,t.next_out-d)),t.data_type=r.bits+(r.last?64:0)+(12===r.mode?128:0)+(20===r.mode||15===r.mode?256:0),(0==f&&0===d||4===e)&&x===N&&(x=-5),x)},r.inflateEnd=function(t){if(!t||!t.state)return U;var e=t.state;return e.window&&(e.window=null),t.state=null,N},r.inflateGetHeader=function(t,e){var r;return t&&t.state?0==(2&(r=t.state).wrap)?U:((r.head=e).done=!1,N):U},r.inflateSetDictionary=function(t,e){var r,i=e.length;return t&&t.state?0!==(r=t.state).wrap&&11!==r.mode?U:11===r.mode&&O(1,e,i,0)!==r.check?-3:Z(t,e,i,i)?(r.mode=31,-4):(r.havedict=1,N):U},r.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./inffast":48,"./inftrees":50}],50:[function(t,e,r){"use strict";var D=t("../utils/common"),F=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],N=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],U=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],P=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];e.exports=function(t,e,r,i,n,s,a,o){var h,u,l,f,d,c,p,m,_,g=o.bits,b=0,v=0,y=0,w=0,k=0,x=0,S=0,z=0,C=0,E=0,A=null,I=0,O=new D.Buf16(16),B=new D.Buf16(16),R=null,T=0;for(b=0;b<=15;b++)O[b]=0;for(v=0;v<i;v++)O[e[r+v]]++;for(k=g,w=15;1<=w&&0===O[w];w--);if(w<k&&(k=w),0===w)return n[s++]=20971520,n[s++]=20971520,o.bits=1,0;for(y=1;y<w&&0===O[y];y++);for(k<y&&(k=y),b=z=1;b<=15;b++)if(z<<=1,(z-=O[b])<0)return-1;if(0<z&&(0===t||1!==w))return-1;for(B[1]=0,b=1;b<15;b++)B[b+1]=B[b]+O[b];for(v=0;v<i;v++)0!==e[r+v]&&(a[B[e[r+v]]++]=v);if(c=0===t?(A=R=a,19):1===t?(A=F,I-=257,R=N,T-=257,256):(A=U,R=P,-1),b=y,d=s,S=v=E=0,l=-1,f=(C=1<<(x=k))-1,1===t&&852<C||2===t&&592<C)return 1;for(;;){for(p=b-S,_=a[v]<c?(m=0,a[v]):a[v]>c?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<<b-S,y=u=1<<x;n[d+(E>>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<<b-1;E&h;)h>>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=e[r+a[v]]}if(k<b&&(E&f)!==l){for(0===S&&(S=k),d+=y,z=1<<(x=b-S);x+S<w&&!((z-=O[x+S])<=0);)x++,z<<=1;if(C+=1<<x,1===t&&852<C||2===t&&592<C)return 1;n[l=E&f]=k<<24|x<<16|d-s|0}}return 0!==E&&(n[d+E]=b-S<<24|64<<16|0),o.bits=k,0}},{"../utils/common":41}],51:[function(t,e,r){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],52:[function(t,e,r){"use strict";var n=t("../utils/common"),o=0,h=1;function i(t){for(var e=t.length;0<=--e;)t[e]=0}var s=0,a=29,u=256,l=u+1+a,f=30,d=19,_=2*l+1,g=15,c=16,p=7,m=256,b=16,v=17,y=18,w=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],k=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],x=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],z=new Array(2*(l+2));i(z);var C=new Array(2*f);i(C);var E=new Array(512);i(E);var A=new Array(256);i(A);var I=new Array(a);i(I);var O,B,R,T=new Array(f);function D(t,e,r,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=r,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function F(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function N(t){return t<256?E[t]:E[256+(t>>>7)]}function U(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function P(t,e,r){t.bi_valid>c-r?(t.bi_buf|=e<<t.bi_valid&65535,U(t,t.bi_buf),t.bi_buf=e>>c-t.bi_valid,t.bi_valid+=r-c):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=r)}function L(t,e,r){P(t,r[2*e],r[2*e+1])}function j(t,e){for(var r=0;r|=1&t,t>>>=1,r<<=1,0<--e;);return r>>>1}function Z(t,e,r){var i,n,s=new Array(g+1),a=0;for(i=1;i<=g;i++)s[i]=a=a+r[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=j(s[o]++,o))}}function W(t){var e;for(e=0;e<l;e++)t.dyn_ltree[2*e]=0;for(e=0;e<f;e++)t.dyn_dtree[2*e]=0;for(e=0;e<d;e++)t.bl_tree[2*e]=0;t.dyn_ltree[2*m]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function M(t){8<t.bi_valid?U(t,t.bi_buf):0<t.bi_valid&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function H(t,e,r,i){var n=2*e,s=2*r;return t[n]<t[s]||t[n]===t[s]&&i[e]<=i[r]}function G(t,e,r){for(var i=t.heap[r],n=r<<1;n<=t.heap_len&&(n<t.heap_len&&H(e,t.heap[n+1],t.heap[n],t.depth)&&n++,!H(e,i,t.heap[n],t.depth));)t.heap[r]=t.heap[n],r=n,n<<=1;t.heap[r]=i}function K(t,e,r){var i,n,s,a,o=0;if(0!==t.last_lit)for(;i=t.pending_buf[t.d_buf+2*o]<<8|t.pending_buf[t.d_buf+2*o+1],n=t.pending_buf[t.l_buf+o],o++,0===i?L(t,n,e):(L(t,(s=A[n])+u+1,e),0!==(a=w[s])&&P(t,n-=I[s],a),L(t,s=N(--i),r),0!==(a=k[s])&&P(t,i-=T[s],a)),o<t.last_lit;);L(t,m,e)}function Y(t,e){var r,i,n,s=e.dyn_tree,a=e.stat_desc.static_tree,o=e.stat_desc.has_stree,h=e.stat_desc.elems,u=-1;for(t.heap_len=0,t.heap_max=_,r=0;r<h;r++)0!==s[2*r]?(t.heap[++t.heap_len]=u=r,t.depth[r]=0):s[2*r+1]=0;for(;t.heap_len<2;)s[2*(n=t.heap[++t.heap_len]=u<2?++u:0)]=1,t.depth[n]=0,t.opt_len--,o&&(t.static_len-=a[2*n+1]);for(e.max_code=u,r=t.heap_len>>1;1<=r;r--)G(t,s,r);for(n=h;r=t.heap[1],t.heap[1]=t.heap[t.heap_len--],G(t,s,1),i=t.heap[1],t.heap[--t.heap_max]=r,t.heap[--t.heap_max]=i,s[2*n]=s[2*r]+s[2*i],t.depth[n]=(t.depth[r]>=t.depth[i]?t.depth[r]:t.depth[i])+1,s[2*r+1]=s[2*i+1]=n,t.heap[1]=n++,G(t,s,1),2<=t.heap_len;);t.heap[--t.heap_max]=t.heap[1],function(t,e){var r,i,n,s,a,o,h=e.dyn_tree,u=e.max_code,l=e.stat_desc.static_tree,f=e.stat_desc.has_stree,d=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,p=e.stat_desc.max_length,m=0;for(s=0;s<=g;s++)t.bl_count[s]=0;for(h[2*t.heap[t.heap_max]+1]=0,r=t.heap_max+1;r<_;r++)p<(s=h[2*h[2*(i=t.heap[r])+1]+1]+1)&&(s=p,m++),h[2*i+1]=s,u<i||(t.bl_count[s]++,a=0,c<=i&&(a=d[i-c]),o=h[2*i],t.opt_len+=o*(s+a),f&&(t.static_len+=o*(l[2*i+1]+a)));if(0!==m){do{for(s=p-1;0===t.bl_count[s];)s--;t.bl_count[s]--,t.bl_count[s+1]+=2,t.bl_count[p]--,m-=2}while(0<m);for(s=p;0!==s;s--)for(i=t.bl_count[s];0!==i;)u<(n=t.heap[--r])||(h[2*n+1]!==s&&(t.opt_len+=(s-h[2*n+1])*h[2*n],h[2*n+1]=s),i--)}}(t,e),Z(s,u,t.bl_count)}function X(t,e,r){var i,n,s=-1,a=e[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),e[2*(r+1)+1]=65535,i=0;i<=r;i++)n=a,a=e[2*(i+1)+1],++o<h&&n===a||(o<u?t.bl_tree[2*n]+=o:0!==n?(n!==s&&t.bl_tree[2*n]++,t.bl_tree[2*b]++):o<=10?t.bl_tree[2*v]++:t.bl_tree[2*y]++,s=n,u=(o=0)===a?(h=138,3):n===a?(h=6,3):(h=7,4))}function V(t,e,r){var i,n,s=-1,a=e[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),i=0;i<=r;i++)if(n=a,a=e[2*(i+1)+1],!(++o<h&&n===a)){if(o<u)for(;L(t,n,t.bl_tree),0!=--o;);else 0!==n?(n!==s&&(L(t,n,t.bl_tree),o--),L(t,b,t.bl_tree),P(t,o-3,2)):o<=10?(L(t,v,t.bl_tree),P(t,o-3,3)):(L(t,y,t.bl_tree),P(t,o-11,7));s=n,u=(o=0)===a?(h=138,3):n===a?(h=6,3):(h=7,4)}}i(T);var q=!1;function J(t,e,r,i){P(t,(s<<1)+(i?1:0),3),function(t,e,r,i){M(t),i&&(U(t,r),U(t,~r)),n.arraySet(t.pending_buf,t.window,e,r,t.pending),t.pending+=r}(t,e,r,!0)}r._tr_init=function(t){q||(function(){var t,e,r,i,n,s=new Array(g+1);for(i=r=0;i<a-1;i++)for(I[i]=r,t=0;t<1<<w[i];t++)A[r++]=i;for(A[r-1]=i,i=n=0;i<16;i++)for(T[i]=n,t=0;t<1<<k[i];t++)E[n++]=i;for(n>>=7;i<f;i++)for(T[i]=n<<7,t=0;t<1<<k[i]-7;t++)E[256+n++]=i;for(e=0;e<=g;e++)s[e]=0;for(t=0;t<=143;)z[2*t+1]=8,t++,s[8]++;for(;t<=255;)z[2*t+1]=9,t++,s[9]++;for(;t<=279;)z[2*t+1]=7,t++,s[7]++;for(;t<=287;)z[2*t+1]=8,t++,s[8]++;for(Z(z,l+1,s),t=0;t<f;t++)C[2*t+1]=5,C[2*t]=j(t,5);O=new D(z,w,u+1,l,g),B=new D(C,k,0,f,g),R=new D(new Array(0),x,0,d,p)}(),q=!0),t.l_desc=new F(t.dyn_ltree,O),t.d_desc=new F(t.dyn_dtree,B),t.bl_desc=new F(t.bl_tree,R),t.bi_buf=0,t.bi_valid=0,W(t)},r._tr_stored_block=J,r._tr_flush_block=function(t,e,r,i){var n,s,a=0;0<t.level?(2===t.strm.data_type&&(t.strm.data_type=function(t){var e,r=4093624447;for(e=0;e<=31;e++,r>>>=1)if(1&r&&0!==t.dyn_ltree[2*e])return o;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return h;for(e=32;e<u;e++)if(0!==t.dyn_ltree[2*e])return h;return o}(t)),Y(t,t.l_desc),Y(t,t.d_desc),a=function(t){var e;for(X(t,t.dyn_ltree,t.l_desc.max_code),X(t,t.dyn_dtree,t.d_desc.max_code),Y(t,t.bl_desc),e=d-1;3<=e&&0===t.bl_tree[2*S[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(t),n=t.opt_len+3+7>>>3,(s=t.static_len+3+7>>>3)<=n&&(n=s)):n=s=r+5,r+4<=n&&-1!==e?J(t,e,r,i):4===t.strategy||s===n?(P(t,2+(i?1:0),3),K(t,z,C)):(P(t,4+(i?1:0),3),function(t,e,r,i){var n;for(P(t,e-257,5),P(t,r-1,5),P(t,i-4,4),n=0;n<i;n++)P(t,t.bl_tree[2*S[n]+1],3);V(t,t.dyn_ltree,e-1),V(t,t.dyn_dtree,r-1)}(t,t.l_desc.max_code+1,t.d_desc.max_code+1,a+1),K(t,t.dyn_ltree,t.dyn_dtree)),W(t),i&&M(t)},r._tr_tally=function(t,e,r){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&r,t.last_lit++,0===e?t.dyn_ltree[2*r]++:(t.matches++,e--,t.dyn_ltree[2*(A[r]+u+1)]++,t.dyn_dtree[2*N(e)]++),t.last_lit===t.lit_bufsize-1},r._tr_align=function(t){P(t,2,3),L(t,m,z),function(t){16===t.bi_valid?(U(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):8<=t.bi_valid&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}(t)}},{"../utils/common":41}],53:[function(t,e,r){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(t,e,r){"use strict";e.exports="function"==typeof setImmediate?setImmediate:function(){var t=[].slice.apply(arguments);t.splice(1,0,0),setTimeout.apply(null,t)}},{}]},{},[10])(10)});
\ No newline at end of file
diff --git a/java/doc/member-search-index.js b/java/doc/member-search-index.js
new file mode 100644 (file)
index 0000000..c1c104f
--- /dev/null
@@ -0,0 +1 @@
+memberSearchIndex = [{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"bufSize(int, int, int)","url":"bufSize(int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"bufSizeYUV(int, int, int, int)","url":"bufSizeYUV(int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"cf"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"close()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"close()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"compress()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"compress(byte[], int)","url":"compress(byte[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"compress(byte[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"compress(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"CS_CMYK"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"CS_GRAY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"CS_RGB"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"CS_YCbCr"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"CS_YCCK"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCustomFilter","l":"customFilter(ShortBuffer, Rectangle, Rectangle, int, int, TJTransform)","url":"customFilter(java.nio.ShortBuffer,java.awt.Rectangle,java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJTransform)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress(BufferedImage, int)","url":"decompress(java.awt.image.BufferedImage,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress(byte[], int, int, int, int, int, int, int)","url":"decompress(byte[],int,int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress(int, int, int, int, int)","url":"decompress(int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress(int, int, int, int)","url":"decompress(int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress(int[], int, int, int, int, int, int, int)","url":"decompress(int[],int,int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress12(int, int)","url":"decompress12(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress12(short[], int, int, int, int)","url":"decompress12(short[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress16(int, int)","url":"decompress16(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress16(short[], int, int, int, int)","url":"decompress16(short[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress8(BufferedImage)","url":"decompress8(java.awt.image.BufferedImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress8(byte[], int, int, int, int)","url":"decompress8(byte[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress8(int, int)","url":"decompress8(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress8(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompress8(int[], int, int, int, int)","url":"decompress8(int[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(int, int, int, int)","url":"decompressToYUV(int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(int, int[], int, int)","url":"decompressToYUV(int,int[],int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(int[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(YUVImage, int)","url":"decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"decompressToYUV(YUVImage)","url":"decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(int, int)","url":"encodeYUV(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(int[], int)","url":"encodeYUV(int[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(int[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(YUVImage, int)","url":"encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"encodeYUV(YUVImage)","url":"encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"equals(TJScalingFactor)","url":"equals(org.libjpegturbo.turbojpeg.TJScalingFactor)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"ERR_FATAL"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"ERR_WARNING"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"finalize()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"finalize()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_ACCURATEDCT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_BOTTOMUP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_FASTDCT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_FASTUPSAMPLE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_LIMITSCANS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_PROGRESSIVE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"FLAG_STOPONWARNING"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"get(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"get(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getAlphaOffset(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getBlueOffset(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getBuf()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getColorspace()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"getCompressedSize()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"getDenom()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"getErrorCode()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getGreenOffset(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getHeight()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getHeight()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getJPEGBuf()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getJPEGSize()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getMCUHeight(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getMCUWidth(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"getNum()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getOffsets()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getPad()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getPixelSize(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getPlanes()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getRedOffset(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"getScaled(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getScaledHeight(int, int)","url":"getScaledHeight(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getScaledWidth(int, int)","url":"getScaledWidth(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"getScalingFactors()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getSize()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getStrides()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getSubsamp()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getSubsamp()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"getTransformedSizes()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"getWidth()"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"getWidth()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"isOne()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"NUMCS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"NUMERR"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"NUMOP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"NUMPF"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"NUMSAMP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"op"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_HFLIP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_NONE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_ROT180"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_ROT270"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_ROT90"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_TRANSPOSE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_TRANSVERSE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OP_VFLIP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_ARITHMETIC"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_COPYNONE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_CROP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_GRAY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_NOOUTPUT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_OPTIMIZE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_PERFECT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_PROGRESSIVE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"OPT_TRIM"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"options"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_ARITHMETIC"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_BOTTOMUP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_COLORSPACE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_DENSITYUNITS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_FASTDCT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_FASTUPSAMPLE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_JPEGHEIGHT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_JPEGWIDTH"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_LOSSLESS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_LOSSLESSPSV"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_LOSSLESSPT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_OPTIMIZE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_PRECISION"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_PROGRESSIVE"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_QUALITY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_RESTARTBLOCKS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_RESTARTROWS"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_SCANLIMIT"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_STOPONWARNING"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_SUBSAMP"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_XDENSITY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PARAM_YDENSITY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_ABGR"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_ARGB"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_BGR"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_BGRA"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_BGRX"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_CMYK"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_GRAY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_RGB"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_RGBA"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_RGBX"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_XBGR"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"PF_XRGB"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"planeHeight(int, int, int)","url":"planeHeight(int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"planeSizeYUV(int, int, int, int, int)","url":"planeSizeYUV(int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"planeWidth(int, int, int)","url":"planeWidth(int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_411"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_420"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_422"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_440"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_441"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_444"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_GRAY"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"SAMP_UNKNOWN"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"set(int, int)","url":"set(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"set(int, int)","url":"set(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"setBuf(byte[], int, int, int, int)","url":"setBuf(byte[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"setBuf(byte[][], int[], int, int[], int, int)","url":"setBuf(byte[][],int[],int,int[],int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"setCroppingRegion(Rectangle)","url":"setCroppingRegion(java.awt.Rectangle)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setJPEGQuality(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"setScalingFactor(TJScalingFactor)","url":"setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSourceImage(BufferedImage, int, int, int, int)","url":"setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSourceImage(byte[], int, int, int, int, int, int)","url":"setSourceImage(byte[],int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"setSourceImage(byte[], int)","url":"setSourceImage(byte[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSourceImage(YUVImage)","url":"setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"setSourceImage(YUVImage)","url":"setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSourceImage12(short[], int, int, int, int, int, int)","url":"setSourceImage12(short[],int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSourceImage16(short[], int, int, int, int, int, int)","url":"setSourceImage16(short[],int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"setSubsamp(int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"TJCompressor()","url":"%3Cinit%3E()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"TJCompressor(BufferedImage, int, int, int, int)","url":"%3Cinit%3E(java.awt.image.BufferedImage,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJCompressor","l":"TJCompressor(byte[], int, int, int, int, int, int)","url":"%3Cinit%3E(byte[],int,int,int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"TJDecompressor()","url":"%3Cinit%3E()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"TJDecompressor(byte[], int)","url":"%3Cinit%3E(byte[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"TJDecompressor(byte[])","url":"%3Cinit%3E(byte[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJDecompressor","l":"TJDecompressor(YUVImage)","url":"%3Cinit%3E(org.libjpegturbo.turbojpeg.YUVImage)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"TJException()","url":"%3Cinit%3E()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"TJException(String, int)","url":"%3Cinit%3E(java.lang.String,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"TJException(String, Throwable)","url":"%3Cinit%3E(java.lang.String,java.lang.Throwable)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"TJException(String)","url":"%3Cinit%3E(java.lang.String)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJException","l":"TJException(Throwable)","url":"%3Cinit%3E(java.lang.Throwable)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJScalingFactor","l":"TJScalingFactor(int, int)","url":"%3Cinit%3E(int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"TJTransform()","url":"%3Cinit%3E()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"TJTransform(int, int, int, int, int, int, TJCustomFilter)","url":"%3Cinit%3E(int,int,int,int,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransform","l":"TJTransform(Rectangle, int, int, TJCustomFilter)","url":"%3Cinit%3E(java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"TJTransformer()","url":"%3Cinit%3E()"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"TJTransformer(byte[], int)","url":"%3Cinit%3E(byte[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"TJTransformer(byte[])","url":"%3Cinit%3E(byte[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"transform(byte[][], TJTransform[], int)","url":"transform(byte[][],org.libjpegturbo.turbojpeg.TJTransform[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"transform(byte[][], TJTransform[])","url":"transform(byte[][],org.libjpegturbo.turbojpeg.TJTransform[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"transform(TJTransform[], int)","url":"transform(org.libjpegturbo.turbojpeg.TJTransform[],int)"},{"p":"org.libjpegturbo.turbojpeg","c":"TJTransformer","l":"transform(TJTransform[])","url":"transform(org.libjpegturbo.turbojpeg.TJTransform[])"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"UNCROPPED"},{"p":"org.libjpegturbo.turbojpeg","c":"TJ","l":"UNSCALED"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"YUVImage(byte[], int, int, int, int)","url":"%3Cinit%3E(byte[],int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"YUVImage(byte[][], int[], int, int[], int, int)","url":"%3Cinit%3E(byte[][],int[],int,int[],int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"YUVImage(int, int, int, int)","url":"%3Cinit%3E(int,int,int,int)"},{"p":"org.libjpegturbo.turbojpeg","c":"YUVImage","l":"YUVImage(int, int[], int, int)","url":"%3Cinit%3E(int,int[],int,int)"}]
\ No newline at end of file
diff --git a/java/doc/member-search-index.zip b/java/doc/member-search-index.zip
new file mode 100644 (file)
index 0000000..fcc0a1f
Binary files /dev/null and b/java/doc/member-search-index.zip differ
index 2a3de37..2051ec2 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJ</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":9,"i1":9,"i2":9,"i3":9,"i4":9,"i5":9,"i6":9,"i7":9,"i8":9,"i9":9,"i10":9,"i11":9,"i12":9};
+var tabs = {65535:["t0","All Methods"],1:["t1","Static Methods"],8:["t4","Concrete Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev Class</li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJ.html" target="_top">Frames</a></li>
-<li><a href="TJ.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJ" class="title">Class TJ</h2>
 </div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
 <hr>
-<br>
-<pre>public final class <span class="strong">TJ</span>
+<pre>public final class <span class="typeNameLabel">TJ</span>
 extends java.lang.Object</pre>
 <div class="block">TurboJPEG utility class (cannot be instantiated)</div>
 </li>
@@ -106,394 +140,608 @@ extends java.lang.Object</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- =========== FIELD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="field_summary">
+<li class="blockList"><a id="field.summary">
 <!--   -->
 </a>
 <h3>Field Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Field Summary table, listing fields, and an explanation">
+<table class="memberSummary">
 <caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Field and Description</th>
+<th class="colSecond" scope="col">Field</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_CMYK">CS_CMYK</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#CS_CMYK">CS_CMYK</a></span></code></th>
+<td class="colLast">
 <div class="block">CMYK colorspace.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_GRAY">CS_GRAY</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#CS_GRAY">CS_GRAY</a></span></code></th>
+<td class="colLast">
 <div class="block">Grayscale colorspace.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_RGB">CS_RGB</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#CS_RGB">CS_RGB</a></span></code></th>
+<td class="colLast">
 <div class="block">RGB colorspace.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr">CS_YCbCr</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#CS_YCbCr">CS_YCbCr</a></span></code></th>
+<td class="colLast">
 <div class="block">YCbCr colorspace.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK">CS_YCCK</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#CS_YCCK">CS_YCCK</a></span></code></th>
+<td class="colLast">
 <div class="block">YCCK colorspace.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#ERR_FATAL">ERR_FATAL</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#ERR_FATAL">ERR_FATAL</a></span></code></th>
+<td class="colLast">
 <div class="block">The error was fatal and non-recoverable.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#ERR_WARNING">ERR_WARNING</a></strong></code>
-<div class="block">The error was non-fatal and recoverable, but the image may still be
- corrupt.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#ERR_WARNING">ERR_WARNING</a></span></code></th>
+<td class="colLast">
+<div class="block">The error was non-fatal and recoverable, but the destination image may
+ still be corrupt.</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTDCT"><code>PARAM_FASTDCT</code></a> instead.</div>
+</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_BOTTOMUP"><code>PARAM_BOTTOMUP</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_ACCURATEDCT">FLAG_ACCURATEDCT</a></strong></code>
-<div class="block">Use the most accurate DCT/IDCT algorithm available in the underlying
- codec.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_FASTDCT">FLAG_FASTDCT</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTDCT"><code>PARAM_FASTDCT</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP">FLAG_BOTTOMUP</a></strong></code>
-<div class="block">The uncompressed source/destination image is stored in bottom-up (Windows,
- OpenGL) order, not top-down (X11) order.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTUPSAMPLE"><code>PARAM_FASTUPSAMPLE</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTDCT">FLAG_FASTDCT</a></strong></code>
-<div class="block">Use the fastest DCT/IDCT algorithm available in the underlying codec.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_SCANLIMIT"><code>PARAM_SCANLIMIT</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FASTUPSAMPLE">FLAG_FASTUPSAMPLE</a></strong></code>
-<div class="block">When decompressing an image that was compressed using chrominance
- subsampling, use the fastest chrominance upsampling algorithm available in
- the underlying codec.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_PROGRESSIVE"><code>PARAM_PROGRESSIVE</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCEMMX">FLAG_FORCEMMX</a></strong></code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></span></code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_STOPONWARNING"><code>PARAM_STOPONWARNING</code></a> instead.</div>
+</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE">FLAG_FORCESSE</a></strong></code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#NUMCS">NUMCS</a></span></code></th>
+<td class="colLast">
+<div class="block">The number of JPEG colorspaces</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE2">FLAG_FORCESSE2</a></strong></code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#NUMERR">NUMERR</a></span></code></th>
+<td class="colLast">
+<div class="block">The number of error codes</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_FORCESSE3">FLAG_FORCESSE3</a></strong></code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#NUMPF">NUMPF</a></span></code></th>
+<td class="colLast">
+<div class="block">The number of pixel formats</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_LIMITSCANS">FLAG_LIMITSCANS</a></strong></code>
-<div class="block">Limit the number of progressive JPEG scans that the decompression and
- transform operations will process.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#NUMSAMP">NUMSAMP</a></span></code></th>
+<td class="colLast">
+<div class="block">The number of chrominance subsampling options</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_PROGRESSIVE">FLAG_PROGRESSIVE</a></strong></code>
-<div class="block">Use progressive entropy coding in JPEG images generated by compression and
- transform operations.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_ARITHMETIC">PARAM_ARITHMETIC</a></span></code></th>
+<td class="colLast">
+<div class="block">Arithmetic entropy coding</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING">FLAG_STOPONWARNING</a></strong></code>
-<div class="block">Immediately discontinue the current compression/decompression/transform
- operation if the underlying codec throws a warning (non-fatal error).</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_BOTTOMUP">PARAM_BOTTOMUP</a></span></code></th>
+<td class="colLast">
+<div class="block">Row order in packed-pixel source/destination images</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#NUMCS">NUMCS</a></strong></code>
-<div class="block">The number of JPEG colorspaces</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_COLORSPACE">PARAM_COLORSPACE</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG colorspace</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#NUMERR">NUMERR</a></strong></code>
-<div class="block">The number of error codes</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_DENSITYUNITS">PARAM_DENSITYUNITS</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG pixel density units</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#NUMPF">NUMPF</a></strong></code>
-<div class="block">The number of pixel formats</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_FASTDCT">PARAM_FASTDCT</a></span></code></th>
+<td class="colLast">
+<div class="block">DCT/IDCT algorithm [lossy compression and decompression]</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#NUMSAMP">NUMSAMP</a></strong></code>
-<div class="block">The number of chrominance subsampling options</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_FASTUPSAMPLE">PARAM_FASTUPSAMPLE</a></span></code></th>
+<td class="colLast">
+<div class="block">Chrominance upsampling algorithm [lossy decompression only]</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_ABGR">PF_ABGR</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_JPEGHEIGHT">PARAM_JPEGHEIGHT</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG height (in pixels) [decompression only, read-only]</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_JPEGWIDTH">PARAM_JPEGWIDTH</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG width (in pixels) [decompression only, read-only]</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_LOSSLESS">PARAM_LOSSLESS</a></span></code></th>
+<td class="colLast">
+<div class="block">Lossless JPEG</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_LOSSLESSPSV">PARAM_LOSSLESSPSV</a></span></code></th>
+<td class="colLast">
+<div class="block">Lossless JPEG predictor selection value (PSV)</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_LOSSLESSPT">PARAM_LOSSLESSPT</a></span></code></th>
+<td class="colLast">
+<div class="block">Lossless JPEG point transform (Pt)</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_OPTIMIZE">PARAM_OPTIMIZE</a></span></code></th>
+<td class="colLast">
+<div class="block">Optimized baseline entropy coding [lossy compression only]</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_PRECISION">PARAM_PRECISION</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG data precision (bits per sample) [decompression only, read-only]</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_PROGRESSIVE">PARAM_PROGRESSIVE</a></span></code></th>
+<td class="colLast">
+<div class="block">Progressive entropy coding</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_QUALITY">PARAM_QUALITY</a></span></code></th>
+<td class="colLast">
+<div class="block">Perceptual quality of lossy JPEG images [compression only]</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_RESTARTBLOCKS">PARAM_RESTARTBLOCKS</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG restart marker interval in MCU blocks (lossy) or samples (lossless)
+ [compression only]</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_RESTARTROWS">PARAM_RESTARTROWS</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless)
+ [compression only]</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_SCANLIMIT">PARAM_SCANLIMIT</a></span></code></th>
+<td class="colLast">
+<div class="block">Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
+ transformation]</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_STOPONWARNING">PARAM_STOPONWARNING</a></span></code></th>
+<td class="colLast">
+<div class="block">Error handling behavior</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_SUBSAMP">PARAM_SUBSAMP</a></span></code></th>
+<td class="colLast">
+<div class="block">Chrominance subsampling level</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_XDENSITY">PARAM_XDENSITY</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG horizontal pixel density</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PARAM_YDENSITY">PARAM_YDENSITY</a></span></code></th>
+<td class="colLast">
+<div class="block">JPEG vertical pixel density</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_ABGR">PF_ABGR</a></span></code></th>
+<td class="colLast">
 <div class="block">ABGR pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_ARGB">PF_ARGB</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_ARGB">PF_ARGB</a></span></code></th>
+<td class="colLast">
 <div class="block">ARGB pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_BGR">PF_BGR</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_BGR">PF_BGR</a></span></code></th>
+<td class="colLast">
 <div class="block">BGR pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_BGRA">PF_BGRA</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_BGRA">PF_BGRA</a></span></code></th>
+<td class="colLast">
 <div class="block">BGRA pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX">PF_BGRX</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_BGRX">PF_BGRX</a></span></code></th>
+<td class="colLast">
 <div class="block">BGRX pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_CMYK">PF_CMYK</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_CMYK">PF_CMYK</a></span></code></th>
+<td class="colLast">
 <div class="block">CMYK pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_GRAY">PF_GRAY</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_GRAY">PF_GRAY</a></span></code></th>
+<td class="colLast">
 <div class="block">Grayscale pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB">PF_RGB</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_RGB">PF_RGB</a></span></code></th>
+<td class="colLast">
 <div class="block">RGB pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGBA">PF_RGBA</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_RGBA">PF_RGBA</a></span></code></th>
+<td class="colLast">
 <div class="block">RGBA pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX">PF_RGBX</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_RGBX">PF_RGBX</a></span></code></th>
+<td class="colLast">
 <div class="block">RGBX pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR">PF_XBGR</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_XBGR">PF_XBGR</a></span></code></th>
+<td class="colLast">
 <div class="block">XBGR pixel format.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB">PF_XRGB</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#PF_XRGB">PF_XRGB</a></span></code></th>
+<td class="colLast">
 <div class="block">XRGB pixel format.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_411">SAMP_411</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_411">SAMP_411</a></span></code></th>
+<td class="colLast">
 <div class="block">4:1:1 chrominance subsampling.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_420">SAMP_420</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_420">SAMP_420</a></span></code></th>
+<td class="colLast">
 <div class="block">4:2:0 chrominance subsampling.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_422">SAMP_422</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_422">SAMP_422</a></span></code></th>
+<td class="colLast">
 <div class="block">4:2:2 chrominance subsampling.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_440">SAMP_440</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_440">SAMP_440</a></span></code></th>
+<td class="colLast">
 <div class="block">4:4:0 chrominance subsampling.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444">SAMP_444</a></strong></code>
-<div class="block">4:4:4 chrominance subsampling (no chrominance subsampling).</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_441">SAMP_441</a></span></code></th>
+<td class="colLast">
+<div class="block">4:4:1 chrominance subsampling.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_GRAY">SAMP_GRAY</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_444">SAMP_444</a></span></code></th>
+<td class="colLast">
+<div class="block">4:4:4 chrominance subsampling (no chrominance subsampling).</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_GRAY">SAMP_GRAY</a></span></code></th>
+<td class="colLast">
 <div class="block">Grayscale.</div>
 </td>
 </tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#SAMP_UNKNOWN">SAMP_UNKNOWN</a></span></code></th>
+<td class="colLast">
+<div class="block">Unknown subsampling.</div>
+</td>
+</tr>
+<tr class="altColor">
+<td class="colFirst"><code>static java.awt.Rectangle</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#UNCROPPED">UNCROPPED</a></span></code></th>
+<td class="colLast">
+<div class="block">A <code>java.awt.Rectangle</code> instance that specifies no cropping</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static <a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#UNSCALED">UNSCALED</a></span></code></th>
+<td class="colLast">
+<div class="block">A <a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJScalingFactor</code></a> instance that specifies a scaling factor of 1/1
+ (no scaling)</div>
+</td>
+</tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t1" class="tableTab"><span><a href="javascript:show(1);">Static Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSize(int,%20int,%20int)">bufSize</a></strong>(int&nbsp;width,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#bufSize(int,int,int)">bufSize</a></span>&#8203;(int&nbsp;width,
        int&nbsp;height,
-       int&nbsp;jpegSubsamp)</code>
+       int&nbsp;jpegSubsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the maximum size of the buffer (in bytes) required to hold a JPEG
  image with the given width, height, and level of chrominance subsampling.</div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int)">bufSizeYUV</a></strong>(int&nbsp;width,
-          int&nbsp;height,
-          int&nbsp;subsamp)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>bufSizeYUV(int, int, int, int)</code></a> instead.</i></div>
-</div>
-</td>
-</tr>
-<tr class="altColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)">bufSizeYUV</a></strong>(int&nbsp;width,
-          int&nbsp;pad,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#bufSizeYUV(int,int,int,int)">bufSizeYUV</a></span>&#8203;(int&nbsp;width,
+          int&nbsp;align,
           int&nbsp;height,
-          int&nbsp;subsamp)</code>
-<div class="block">Returns the size of the buffer (in bytes) required to hold a YUV planar
- image with the given width, height, and level of chrominance subsampling.</div>
+          int&nbsp;subsamp)</code></th>
+<td class="colLast">
+<div class="block">Returns the size of the buffer (in bytes) required to hold a unified
+ planar YUV image with the given width, height, and level of chrominance
+ subsampling.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i2" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getAlphaOffset(int)">getAlphaOffset</a></strong>(int&nbsp;pixelFormat)</code>
-<div class="block">For the given pixel format, returns the number of bytes that the alpha
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getAlphaOffset(int)">getAlphaOffset</a></span>&#8203;(int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">For the given pixel format, returns the number of samples that the alpha
  component is offset from the start of the pixel.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i3" class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getBlueOffset(int)">getBlueOffset</a></strong>(int&nbsp;pixelFormat)</code>
-<div class="block">For the given pixel format, returns the number of bytes that the blue
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getBlueOffset(int)">getBlueOffset</a></span>&#8203;(int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">For the given pixel format, returns the number of samples that the blue
  component is offset from the start of the pixel.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i4" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getGreenOffset(int)">getGreenOffset</a></strong>(int&nbsp;pixelFormat)</code>
-<div class="block">For the given pixel format, returns the number of bytes that the green
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getGreenOffset(int)">getGreenOffset</a></span>&#8203;(int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">For the given pixel format, returns the number of samples that the green
  component is offset from the start of the pixel.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i5" class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUHeight(int)">getMCUHeight</a></strong>(int&nbsp;subsamp)</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getMCUHeight(int)">getMCUHeight</a></span>&#8203;(int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the MCU block height for the given level of chrominance
  subsampling.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i6" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUWidth(int)">getMCUWidth</a></strong>(int&nbsp;subsamp)</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getMCUWidth(int)">getMCUWidth</a></span>&#8203;(int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the MCU block width for the given level of chrominance
  subsampling.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i7" class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getPixelSize(int)">getPixelSize</a></strong>(int&nbsp;pixelFormat)</code>
-<div class="block">Returns the pixel size (in bytes) for the given pixel format.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getPixelSize(int)">getPixelSize</a></span>&#8203;(int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Returns the pixel size (in samples) for the given pixel format.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i8" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getRedOffset(int)">getRedOffset</a></strong>(int&nbsp;pixelFormat)</code>
-<div class="block">For the given pixel format, returns the number of bytes that the red
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getRedOffset(int)">getRedOffset</a></span>&#8203;(int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">For the given pixel format, returns the number of samples that the red
  component is offset from the start of the pixel.</div>
 </td>
 </tr>
-<tr class="altColor">
-<td class="colFirst"><code>static <a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getScalingFactors()">getScalingFactors</a></strong>()</code>
-<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor in
- this implementation of TurboJPEG supports.</div>
+<tr id="i9" class="rowColor">
+<td class="colFirst"><code>static <a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>[]</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getScalingFactors()">getScalingFactors</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor
+ supports.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i10" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#planeHeight(int,%20int,%20int)">planeHeight</a></strong>(int&nbsp;componentID,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#planeHeight(int,int,int)">planeHeight</a></span>&#8203;(int&nbsp;componentID,
            int&nbsp;height,
-           int&nbsp;subsamp)</code>
+           int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the plane height of a YUV image plane with the given parameters.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i11" class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#planeSizeYUV(int,%20int,%20int,%20int,%20int)">planeSizeYUV</a></strong>(int&nbsp;componentID,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#planeSizeYUV(int,int,int,int,int)">planeSizeYUV</a></span>&#8203;(int&nbsp;componentID,
             int&nbsp;width,
             int&nbsp;stride,
             int&nbsp;height,
-            int&nbsp;subsamp)</code>
+            int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the size of the buffer (in bytes) required to hold a YUV image
  plane with the given parameters.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i12" class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJ.html#planeWidth(int,%20int,%20int)">planeWidth</a></strong>(int&nbsp;componentID,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#planeWidth(int,int,int)">planeWidth</a></span>&#8203;(int&nbsp;componentID,
           int&nbsp;width,
-          int&nbsp;subsamp)</code>
+          int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Returns the plane width of a YUV image plane with the given parameters.</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -501,6 +749,7 @@ extends java.lang.Object</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -508,12 +757,13 @@ extends java.lang.Object</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ============ FIELD DETAIL =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="field_detail">
+<li class="blockList"><a id="field.detail">
 <!--   -->
 </a>
 <h3>Field Detail</h3>
-<a name="NUMSAMP">
+<a id="NUMSAMP">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -521,10 +771,13 @@ extends java.lang.Object</pre>
 <h4>NUMSAMP</h4>
 <pre>public static final&nbsp;int NUMSAMP</pre>
 <div class="block">The number of chrominance subsampling options</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMSAMP">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMSAMP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_444">
+<a id="SAMP_444">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -534,10 +787,13 @@ extends java.lang.Object</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_444">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_444">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_422">
+<a id="SAMP_422">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -546,10 +802,13 @@ extends java.lang.Object</pre>
 <pre>public static final&nbsp;int SAMP_422</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_422">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_422">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_420">
+<a id="SAMP_420">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -558,10 +817,13 @@ extends java.lang.Object</pre>
 <pre>public static final&nbsp;int SAMP_420</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_420">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_420">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_GRAY">
+<a id="SAMP_GRAY">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -569,10 +831,13 @@ extends java.lang.Object</pre>
 <h4>SAMP_GRAY</h4>
 <pre>public static final&nbsp;int SAMP_GRAY</pre>
 <div class="block">Grayscale.  The JPEG or YUV image will contain no chrominance components.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_GRAY">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_GRAY">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_440">
+<a id="SAMP_440">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -582,10 +847,13 @@ extends java.lang.Object</pre>
 <div class="block">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 that 4:4:0 subsampling is not fully accelerated in libjpeg-turbo.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_440">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_440">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="SAMP_411">
+<a id="SAMP_411">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -600,10 +868,56 @@ extends java.lang.Object</pre>
  perceptual quality.  However, 4:1:1 is better able to reproduce sharp
  horizontal features.  Note that 4:1:1 subsampling is not fully accelerated
  in libjpeg-turbo.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_411">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_411">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="NUMPF">
+<a id="SAMP_441">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>SAMP_441</h4>
+<pre>public static final&nbsp;int SAMP_441</pre>
+<div class="block">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.
+ JPEG images compressed with 4:4: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:4:1 is better able to reproduce sharp
+ vertical features.  Note that 4:4:1 subsampling is not fully accelerated
+ in libjpeg-turbo.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_441">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="SAMP_UNKNOWN">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>SAMP_UNKNOWN</h4>
+<pre>public static final&nbsp;int SAMP_UNKNOWN</pre>
+<div class="block">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
+ <ul>
+ <li> decompressed into planar YUV images,
+ <li> losslessly transformed if <a href="TJTransform.html#OPT_CROP"><code>TJTransform.OPT_CROP</code></a> is specified,
+ or
+ <li> partially decompressed using a cropping region.
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.SAMP_UNKNOWN">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="NUMPF">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -611,10 +925,13 @@ extends java.lang.Object</pre>
 <h4>NUMPF</h4>
 <pre>public static final&nbsp;int NUMPF</pre>
 <div class="block">The number of pixel formats</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMPF">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMPF">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_RGB">
+<a id="PF_RGB">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -622,12 +939,15 @@ extends java.lang.Object</pre>
 <h4>PF_RGB</h4>
 <pre>public static final&nbsp;int PF_RGB</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGB">Constant Field Values</a></dd></dl>
+ stored in 3-sample pixels in the order R, G, B from lowest to highest
+ memory address within each pixel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGB">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_BGR">
+<a id="PF_BGR">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -635,12 +955,15 @@ extends java.lang.Object</pre>
 <h4>PF_BGR</h4>
 <pre>public static final&nbsp;int PF_BGR</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGR">Constant Field Values</a></dd></dl>
+ stored in 3-sample pixels in the order B, G, R from lowest to highest
+ memory address within each pixel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGR">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_RGBX">
+<a id="PF_RGBX">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -648,13 +971,16 @@ extends java.lang.Object</pre>
 <h4>PF_RGBX</h4>
 <pre>public static final&nbsp;int PF_RGBX</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGBX">Constant Field Values</a></dd></dl>
+ 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 and undefined when decompressing.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGBX">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_BGRX">
+<a id="PF_BGRX">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -662,13 +988,16 @@ extends java.lang.Object</pre>
 <h4>PF_BGRX</h4>
 <pre>public static final&nbsp;int PF_BGRX</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGRX">Constant Field Values</a></dd></dl>
+ 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 and undefined when decompressing.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGRX">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_XBGR">
+<a id="PF_XBGR">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -676,13 +1005,16 @@ extends java.lang.Object</pre>
 <h4>PF_XBGR</h4>
 <pre>public static final&nbsp;int PF_XBGR</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_XBGR">Constant Field Values</a></dd></dl>
+ 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 and undefined when decompressing.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_XBGR">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_XRGB">
+<a id="PF_XRGB">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -690,77 +1022,96 @@ extends java.lang.Object</pre>
 <h4>PF_XRGB</h4>
 <pre>public static final&nbsp;int PF_XRGB</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_XRGB">Constant Field Values</a></dd></dl>
+ 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 and undefined when decompressing.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_XRGB">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_GRAY">
+<a id="PF_GRAY">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>PF_GRAY</h4>
 <pre>public static final&nbsp;int PF_GRAY</pre>
-<div class="block">Grayscale pixel format.  Each 1-byte pixel represents a luminance
- (brightness) level from 0 to 255.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_GRAY">Constant Field Values</a></dd></dl>
+<div class="block">Grayscale pixel format.  Each 1-sample pixel represents a luminance
+ (brightness) level from 0 to the maximum sample value (255 for 8-bit
+ samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.)</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_GRAY">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_RGBA">
+<a id="PF_RGBA">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>PF_RGBA</h4>
 <pre>public static final&nbsp;int PF_RGBA</pre>
-<div class="block">RGBA pixel format.  This is the same as <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGBX"><code>PF_RGBX</code></a>, except that when
- decompressing, the X byte is guaranteed to be 0xFF, which can be
- interpreted as an opaque alpha channel.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGBA">Constant Field Values</a></dd></dl>
+<div class="block">RGBA pixel format.  This is the same as <a href="#PF_RGBX"><code>PF_RGBX</code></a>, except that when
+ decompressing, the X component is guaranteed to be equal to the maximum
+ sample value, which can be interpreted as an opaque alpha channel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_RGBA">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_BGRA">
+<a id="PF_BGRA">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>PF_BGRA</h4>
 <pre>public static final&nbsp;int PF_BGRA</pre>
-<div class="block">BGRA pixel format.  This is the same as <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_BGRX"><code>PF_BGRX</code></a>, except that when
- decompressing, the X byte is guaranteed to be 0xFF, which can be
- interpreted as an opaque alpha channel.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGRA">Constant Field Values</a></dd></dl>
+<div class="block">BGRA pixel format.  This is the same as <a href="#PF_BGRX"><code>PF_BGRX</code></a>, except that when
+ decompressing, the X component is guaranteed to be equal to the maximum
+ sample value, which can be interpreted as an opaque alpha channel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_BGRA">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_ABGR">
+<a id="PF_ABGR">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>PF_ABGR</h4>
 <pre>public static final&nbsp;int PF_ABGR</pre>
-<div class="block">ABGR pixel format.  This is the same as <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_XBGR"><code>PF_XBGR</code></a>, except that when
- decompressing, the X byte is guaranteed to be 0xFF, which can be
- interpreted as an opaque alpha channel.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_ABGR">Constant Field Values</a></dd></dl>
+<div class="block">ABGR pixel format.  This is the same as <a href="#PF_XBGR"><code>PF_XBGR</code></a>, except that when
+ decompressing, the X component is guaranteed to be equal to the maximum
+ sample value, which can be interpreted as an opaque alpha channel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_ABGR">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_ARGB">
+<a id="PF_ARGB">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>PF_ARGB</h4>
 <pre>public static final&nbsp;int PF_ARGB</pre>
-<div class="block">ARGB pixel format.  This is the same as <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_XRGB"><code>PF_XRGB</code></a>, except that when
- decompressing, the X byte is guaranteed to be 0xFF, which can be
- interpreted as an opaque alpha channel.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_ARGB">Constant Field Values</a></dd></dl>
+<div class="block">ARGB pixel format.  This is the same as <a href="#PF_XRGB"><code>PF_XRGB</code></a>, except that when
+ decompressing, the X component is guaranteed to be equal to the maximum
+ sample value, which can be interpreted as an opaque alpha channel.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_ARGB">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="PF_CMYK">
+<a id="PF_CMYK">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -778,12 +1129,15 @@ extends java.lang.Object</pre>
  vice versa, but the mapping is typically not 1:1 or reversible, nor can it
  be defined with a simple formula.  Thus, such a conversion is out of scope
  for a codec library.  However, the TurboJPEG API allows for compressing
- CMYK pixels into a YCCK JPEG image (see <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK"><code>CS_YCCK</code></a>) and
- decompressing YCCK JPEG images into CMYK pixels.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_CMYK">Constant Field Values</a></dd></dl>
+ packed-pixel CMYK images into YCCK JPEG images (see <a href="#CS_YCCK"><code>CS_YCCK</code></a>) and
+ decompressing YCCK JPEG images into packed-pixel CMYK images.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PF_CMYK">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="NUMCS">
+<a id="NUMCS">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -791,10 +1145,13 @@ extends java.lang.Object</pre>
 <h4>NUMCS</h4>
 <pre>public static final&nbsp;int NUMCS</pre>
 <div class="block">The number of JPEG colorspaces</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMCS">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMCS">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="CS_RGB">
+<a id="CS_RGB">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -804,12 +1161,16 @@ extends java.lang.Object</pre>
 <div class="block">RGB colorspace.  When compressing the JPEG image, the R, G, and B
  components in the source image are reordered into image planes, but no
  colorspace conversion or subsampling is performed.  RGB JPEG images can be
- decompressed to any of the extended RGB pixel formats or grayscale, but
- they cannot be decompressed to YUV images.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_RGB">Constant Field Values</a></dd></dl>
+ compressed from and decompressed to packed-pixel images with any of the
+ extended RGB or grayscale pixel formats, but they cannot be compressed
+ from or decompressed to planar YUV images.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_RGB">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="CS_YCbCr">
+<a id="CS_YCbCr">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -826,14 +1187,18 @@ extends java.lang.Object</pre>
  transformation allowed the same signal to drive both black &amp; white and
  color televisions, but JPEG images use YCbCr primarily because it allows
  the color data to be optionally subsampled for the purposes of reducing
- bandwidth or disk space.  YCbCr is the most common JPEG colorspace, and
- YCbCr JPEG images can be compressed from and decompressed to any of the
- extended RGB pixel formats or grayscale, or they can be decompressed to
- YUV planar images.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_YCbCr">Constant Field Values</a></dd></dl>
+ 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.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_YCbCr">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="CS_GRAY">
+<a id="CS_GRAY">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -842,13 +1207,17 @@ extends java.lang.Object</pre>
 <pre>public static final&nbsp;int CS_GRAY</pre>
 <div class="block">Grayscale colorspace.  The JPEG image retains only the luminance data (Y
  component), and any color data from the source image is discarded.
- Grayscale JPEG images can be compressed from and decompressed to any of
- the extended RGB pixel formats or grayscale, or they can be decompressed
- to YUV planar images.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_GRAY">Constant Field Values</a></dd></dl>
+ 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.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_GRAY">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="CS_CMYK">
+<a id="CS_CMYK">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -858,11 +1227,15 @@ extends java.lang.Object</pre>
 <div class="block">CMYK colorspace.  When compressing the JPEG image, the C, M, Y, and K
  components in the source image are reordered into image planes, but no
  colorspace conversion or subsampling is performed.  CMYK JPEG images can
- only be decompressed to CMYK pixels.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_CMYK">Constant Field Values</a></dd></dl>
+ only be compressed from and decompressed to packed-pixel images with the
+ CMYK pixel format.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_CMYK">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="CS_YCCK">
+<a id="CS_YCCK">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -875,169 +1248,718 @@ extends java.lang.Object</pre>
  reversibly transformed into YCCK, and as with YCbCr, the chrominance
  components in the YCCK pixels can be subsampled without incurring major
  perceptual loss.  YCCK JPEG images can only be compressed from and
- decompressed to CMYK pixels.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_YCCK">Constant Field Values</a></dd></dl>
+ decompressed to packed-pixel images with the CMYK pixel format.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.CS_YCCK">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_BOTTOMUP">
+<a id="PARAM_STOPONWARNING">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>FLAG_BOTTOMUP</h4>
-<pre>public static final&nbsp;int FLAG_BOTTOMUP</pre>
-<div class="block">The uncompressed source/destination image is stored in bottom-up (Windows,
- OpenGL) order, not top-down (X11) order.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_BOTTOMUP">Constant Field Values</a></dd></dl>
+<h4>PARAM_STOPONWARNING</h4>
+<pre>public static final&nbsp;int PARAM_STOPONWARNING</pre>
+<div class="block">Error handling behavior
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default]</i> Allow the current
+ compression/decompression/transform operation to complete unless a fatal
+ error is encountered.
+ <li> <code>1</code> Immediately discontinue the current
+ compression/decompression/transform operation if a warning (non-fatal
+ error) occurs.
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_STOPONWARNING">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FORCEMMX">
+<a id="PARAM_BOTTOMUP">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>FLAG_FORCEMMX</h4>
-<pre>@Deprecated
-public static final&nbsp;int FLAG_FORCEMMX</pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FORCEMMX">Constant Field Values</a></dd></dl>
+<h4>PARAM_BOTTOMUP</h4>
+<pre>public static final&nbsp;int PARAM_BOTTOMUP</pre>
+<div class="block">Row order in packed-pixel source/destination images
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default]</i> top-down (X11) order
+ <li> <code>1</code> bottom-up (Windows, OpenGL) order
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_BOTTOMUP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FORCESSE">
+<a id="PARAM_QUALITY">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>FLAG_FORCESSE</h4>
-<pre>@Deprecated
-public static final&nbsp;int FLAG_FORCESSE</pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE">Constant Field Values</a></dd></dl>
+<h4>PARAM_QUALITY</h4>
+<pre>public static final&nbsp;int PARAM_QUALITY</pre>
+<div class="block">Perceptual quality of lossy JPEG images [compression only]
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>1</code>-<code>100</code> (<code>1</code> = worst quality but
+ best compression, <code>100</code> = best quality but worst compression)
+ <i>[no default; must be explicitly specified]</i>
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_QUALITY">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FORCESSE2">
+<a id="PARAM_SUBSAMP">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>FLAG_FORCESSE2</h4>
-<pre>@Deprecated
-public static final&nbsp;int FLAG_FORCESSE2</pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE2">Constant Field Values</a></dd></dl>
+<h4>PARAM_SUBSAMP</h4>
+<pre>public static final&nbsp;int PARAM_SUBSAMP</pre>
+<div class="block">Chrominance subsampling level
+
+ <p>The JPEG or YUV image uses (decompression, decoding) or will use (lossy
+ compression, encoding) the specified level of chrominance subsampling.
+
+ <p>When pixels are converted from RGB to YCbCr (see <a href="#CS_YCbCr"><code>CS_YCbCr</code></a>) or
+ from CMYK to YCCK (see <a href="#CS_YCCK"><code>CS_YCCK</code></a>) 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".
+
+ <p><b>Value</b>
+ <ul>
+ <li> One of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a> <i>[no default; must be
+ explicitly specified for lossy compression, encoding, and decoding]</i>
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_SUBSAMP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FORCESSE3">
+<a id="PARAM_JPEGWIDTH">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>FLAG_FORCESSE3</h4>
+<h4>PARAM_JPEGWIDTH</h4>
+<pre>public static final&nbsp;int PARAM_JPEGWIDTH</pre>
+<div class="block">JPEG width (in pixels) [decompression only, read-only]</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_JPEGWIDTH">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_JPEGHEIGHT">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_JPEGHEIGHT</h4>
+<pre>public static final&nbsp;int PARAM_JPEGHEIGHT</pre>
+<div class="block">JPEG height (in pixels) [decompression only, read-only]</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_JPEGHEIGHT">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_PRECISION">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_PRECISION</h4>
+<pre>public static final&nbsp;int PARAM_PRECISION</pre>
+<div class="block">JPEG data precision (bits per sample) [decompression only, read-only]
+
+ <p>The JPEG image uses the specified number of bits per sample.
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>8</code>, <code>12</code>, or <code>16</code>
+ </ul>
+
+ <p>12-bit data precision implies <a href="#PARAM_OPTIMIZE"><code>PARAM_OPTIMIZE</code></a> unless
+ <a href="#PARAM_ARITHMETIC"><code>PARAM_ARITHMETIC</code></a> is set.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_PRECISION">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_COLORSPACE">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_COLORSPACE</h4>
+<pre>public static final&nbsp;int PARAM_COLORSPACE</pre>
+<div class="block">JPEG colorspace
+
+ <p>The JPEG image uses (decompression) or will use (lossy compression) the
+ specified colorspace.
+
+ <p><b>Value</b>
+ <ul>
+ <li> One of <a href="#CS_RGB"><code>TJ.CS_*</code></a> <i>[default for lossy compression:
+ automatically selected based on the subsampling level and pixel
+ format]</i>
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_COLORSPACE">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_FASTUPSAMPLE">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_FASTUPSAMPLE</h4>
+<pre>public static final&nbsp;int PARAM_FASTUPSAMPLE</pre>
+<div class="block">Chrominance upsampling algorithm [lossy decompression only]
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default]</i> Use smooth upsampling when
+ decompressing a JPEG image that was compressed using chrominance
+ subsampling.  This creates a smooth transition between neighboring
+ chrominance components in order to reduce upsampling artifacts in the
+ decompressed image.
+ <li> <code>1</code> Use the fastest chrominance upsampling algorithm
+ available, which may combine upsampling with color conversion.
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_FASTUPSAMPLE">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_FASTDCT">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_FASTDCT</h4>
+<pre>public static final&nbsp;int PARAM_FASTDCT</pre>
+<div class="block">DCT/IDCT algorithm [lossy compression and decompression]
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default]</i> Use the most accurate DCT/IDCT
+ algorithm available.
+ <li> <code>1</code> Use the fastest DCT/IDCT algorithm available.
+ </ul>
+
+ <p>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:
+
+ <ul>
+ <li> The "fast" and "accurate" DCT/IDCT algorithms perform similarly on
+ modern x86/x86-64 CPUs that support AVX2 instructions.
+ <li> The "fast" algorithm is generally only about 5-15% faster than the
+ "accurate" algorithm on other types of CPUs.
+ <li> 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.
+ <li> The "fast" algorithm degrades and is not fully accelerated for JPEG
+ quality levels above 97, so it will be slower than the "accurate"
+ algorithm.
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_FASTDCT">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_OPTIMIZE">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_OPTIMIZE</h4>
+<pre>public static final&nbsp;int PARAM_OPTIMIZE</pre>
+<div class="block">Optimized baseline entropy coding [lossy compression only]
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default]</i> The JPEG image will use the default
+ Huffman tables.
+ <li> <code>1</code> Optimal Huffman tables will be computed for the JPEG
+ image.  For lossless transformation, this can also be specified using
+ <a href="TJTransform.html#OPT_OPTIMIZE"><code>TJTransform.OPT_OPTIMIZE</code></a>.
+ </ul>
+
+ <p>Optimized baseline entropy coding will improve compression slightly
+ (generally 5% or less), but it will reduce compression performance
+ considerably.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_OPTIMIZE">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_PROGRESSIVE">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_PROGRESSIVE</h4>
+<pre>public static final&nbsp;int PARAM_PROGRESSIVE</pre>
+<div class="block">Progressive entropy coding
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default for compression, lossless
+ transformation]</i> The lossy JPEG image uses (decompression) or will use
+ (compression, lossless transformation) baseline entropy coding.
+ <li> <code>1</code> The lossy JPEG image uses (decompression) or will use
+ (compression, lossless transformation) progressive entropy coding.  For
+ lossless transformation, this can also be specified using
+ <a href="TJTransform.html#OPT_PROGRESSIVE"><code>TJTransform.OPT_PROGRESSIVE</code></a>.
+ </ul>
+
+ <p>Progressive entropy coding will generally improve compression relative
+ to baseline entropy coding, but it will reduce compression and
+ decompression performance considerably.  Can be combined with
+ <a href="#PARAM_ARITHMETIC"><code>PARAM_ARITHMETIC</code></a>.  Implies <a href="#PARAM_OPTIMIZE"><code>PARAM_OPTIMIZE</code></a> unless
+ <a href="#PARAM_ARITHMETIC"><code>PARAM_ARITHMETIC</code></a> is also set.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_PROGRESSIVE">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_SCANLIMIT">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_SCANLIMIT</h4>
+<pre>public static final&nbsp;int PARAM_SCANLIMIT</pre>
+<div class="block">Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
+ transformation]
+
+ <p>Setting this parameter will cause the decompression and transform
+ functions to return an error if the number of scans in a progressive JPEG
+ image exceeds the specified limit.  The primary purpose of this is to
+ allow security-critical applications to guard against an exploit of the
+ progressive JPEG format described in
+ <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.
+
+ <p><b>Value</b>
+ <ul>
+ <li> maximum number of progressive JPEG scans that the decompression and
+ transform functions will process <i>[default: <code>0</code> (no
+ limit)]</i>
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_PROGRESSIVE"><code>PARAM_PROGRESSIVE</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_SCANLIMIT">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_ARITHMETIC">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_ARITHMETIC</h4>
+<pre>public static final&nbsp;int PARAM_ARITHMETIC</pre>
+<div class="block">Arithmetic entropy coding
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default for compression, lossless
+ transformation]</i> The lossy JPEG image uses (decompression) or will use
+ (compression, lossless transformation) Huffman entropy coding.
+ <li> <code>1</code> The lossy JPEG image uses (decompression) or will use
+ (compression, lossless transformation) arithmetic entropy coding.  For
+ lossless transformation, this can also be specified using
+ <a href="TJTransform.html#OPT_ARITHMETIC"><code>TJTransform.OPT_ARITHMETIC</code></a>.
+ </ul>
+
+ <p>Arithmetic entropy coding will generally improve compression relative
+ to Huffman entropy coding, but it will reduce compression and
+ decompression performance considerably.  Can be combined with
+ <a href="#PARAM_PROGRESSIVE"><code>PARAM_PROGRESSIVE</code></a>.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_ARITHMETIC">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_LOSSLESS">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_LOSSLESS</h4>
+<pre>public static final&nbsp;int PARAM_LOSSLESS</pre>
+<div class="block">Lossless JPEG
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default for compression]</i> The JPEG image is
+ (decompression) or will be (compression) lossy/DCT-based.
+ <li> <code>1</code> The JPEG image is (decompression) or will be
+ (compression) lossless/predictive.
+ </ul>
+
+ <p>In most cases, compressing and decompressing lossless JPEG images is
+ considerably slower than compressing and decompressing lossy JPEG images.
+ Also note that the following features are not available with lossless JPEG
+ images:
+ <ul>
+ <li> Colorspace conversion (lossless JPEG images always use
+ <a href="#CS_RGB"><code>CS_RGB</code></a>, <a href="#CS_GRAY"><code>CS_GRAY</code></a>, or <a href="#CS_CMYK"><code>CS_CMYK</code></a>, depending on the
+ pixel format of the source image)
+ <li> Chrominance subsampling (lossless JPEG images always use
+ <a href="#SAMP_444"><code>SAMP_444</code></a>)
+ <li> JPEG quality selection
+ <li> DCT/IDCT algorithm selection
+ <li> Progressive entropy coding
+ <li> Arithmetic entropy coding
+ <li> Compression from/decompression to planar YUV images
+ <li> Decompression scaling
+ <li> Lossless transformation
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_LOSSLESSPSV"><code>PARAM_LOSSLESSPSV</code></a>, 
+<a href="#PARAM_LOSSLESSPT"><code>PARAM_LOSSLESSPT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESS">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_LOSSLESSPSV">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_LOSSLESSPSV</h4>
+<pre>public static final&nbsp;int PARAM_LOSSLESSPSV</pre>
+<div class="block">Lossless JPEG predictor selection value (PSV)
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>1</code>-<code>7</code> <i>[default for compression:
+ <code>1</code>]</i>
+ </ul></div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_LOSSLESS"><code>PARAM_LOSSLESS</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESSPSV">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_LOSSLESSPT">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_LOSSLESSPT</h4>
+<pre>public static final&nbsp;int PARAM_LOSSLESSPT</pre>
+<div class="block">Lossless JPEG point transform (Pt)
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> through <i><b>precision</b> - 1</i>, where
+ <b><i>precision</i></b> is the JPEG data precision in bits <i>[default for
+ compression: <code>0</code>]</i>
+ </ul>
+
+ <p>A point transform value of <code>0</code> 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.)</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_LOSSLESS"><code>PARAM_LOSSLESS</code></a>, 
+<a href="#PARAM_PRECISION"><code>PARAM_PRECISION</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_LOSSLESSPT">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_RESTARTBLOCKS">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_RESTARTBLOCKS</h4>
+<pre>public static final&nbsp;int PARAM_RESTARTBLOCKS</pre>
+<div class="block">JPEG restart marker interval in MCU blocks (lossy) or samples (lossless)
+ [compression only]
+
+ <p>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.
+
+ <p><b>Value</b>
+ <ul>
+ <li> the number of MCU blocks or samples between each restart marker
+ <i>[default: <code>0</code> (no restart markers)]</i>
+ </ul>
+
+ <p> Setting this parameter to a non-zero value sets
+ <a href="#PARAM_RESTARTROWS"><code>PARAM_RESTARTROWS</code></a> to 0.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_RESTARTBLOCKS">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_RESTARTROWS">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_RESTARTROWS</h4>
+<pre>public static final&nbsp;int PARAM_RESTARTROWS</pre>
+<div class="block">JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless)
+ [compression only]
+
+ <p>See <a href="#PARAM_RESTARTBLOCKS"><code>PARAM_RESTARTBLOCKS</code></a> for a description of restart markers.
+
+ <p><b>Value</b>
+ <ul>
+ <li> the number of MCU rows or sample rows between each restart marker
+ <i>[default: <code>0</code> (no restart markers)]</i>
+ </ul>
+
+ <p>Setting this parameter to a non-zero value sets
+ <a href="#PARAM_RESTARTBLOCKS"><code>PARAM_RESTARTBLOCKS</code></a> to 0.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_RESTARTROWS">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_XDENSITY">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_XDENSITY</h4>
+<pre>public static final&nbsp;int PARAM_XDENSITY</pre>
+<div class="block">JPEG horizontal pixel density
+
+ <p><b>Value</b>
+ <ul>
+ <li> The JPEG image has (decompression) or will have (compression) the
+ specified horizontal pixel density <i>[default for compression:
+ <code>1</code>]</i>.
+ </ul>
+
+ <p>This value is stored in or read from the JPEG header.  It does not
+ affect the contents of the JPEG image.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_DENSITYUNITS"><code>PARAM_DENSITYUNITS</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_XDENSITY">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_YDENSITY">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_YDENSITY</h4>
+<pre>public static final&nbsp;int PARAM_YDENSITY</pre>
+<div class="block">JPEG vertical pixel density
+
+ <p><b>Value</b>
+ <ul>
+ <li> The JPEG image has (decompression) or will have (compression) the
+ specified vertical pixel density <i>[default for compression:
+ <code>1</code>]</i>.
+ </ul>
+
+ <p>This value is stored in or read from the JPEG header.  It does not
+ affect the contents of the JPEG image.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_DENSITYUNITS"><code>PARAM_DENSITYUNITS</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_YDENSITY">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="PARAM_DENSITYUNITS">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>PARAM_DENSITYUNITS</h4>
+<pre>public static final&nbsp;int PARAM_DENSITYUNITS</pre>
+<div class="block">JPEG pixel density units
+
+ <p><b>Value</b>
+ <ul>
+ <li> <code>0</code> <i>[default for compression]</i> The pixel density of
+ the JPEG image is expressed (decompression) or will be expressed
+ (compression) in unknown units.
+ <li> <code>1</code> The pixel density of the JPEG image is expressed
+ (decompression) or will be expressed (compression) in units of
+ pixels/inch.
+ <li> <code>2</code> The pixel density of the JPEG image is expressed
+ (decompression) or will be expressed (compression) in units of pixels/cm.
+ </ul>
+
+ <p>This value is stored in or read from the JPEG header.  It does not
+ affect the contents of the JPEG image.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#PARAM_XDENSITY"><code>PARAM_XDENSITY</code></a>, 
+<a href="#PARAM_YDENSITY"><code>PARAM_YDENSITY</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.PARAM_DENSITYUNITS">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="FLAG_BOTTOMUP">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>FLAG_BOTTOMUP</h4>
 <pre>@Deprecated
-public static final&nbsp;int FLAG_FORCESSE3</pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FORCESSE3">Constant Field Values</a></dd></dl>
+public static final&nbsp;int FLAG_BOTTOMUP</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_BOTTOMUP"><code>PARAM_BOTTOMUP</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_BOTTOMUP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FASTUPSAMPLE">
+<a id="FLAG_FASTUPSAMPLE">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_FASTUPSAMPLE</h4>
-<pre>public static final&nbsp;int FLAG_FASTUPSAMPLE</pre>
-<div class="block">When decompressing an image that was compressed using chrominance
- subsampling, use the fastest chrominance upsampling algorithm available in
- the underlying codec.  The default is to use smooth upsampling, which
- creates a smooth transition between neighboring chrominance components in
- order to reduce upsampling artifacts in the decompressed image.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FASTUPSAMPLE">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_FASTUPSAMPLE</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTUPSAMPLE"><code>PARAM_FASTUPSAMPLE</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FASTUPSAMPLE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_FASTDCT">
+<a id="FLAG_FASTDCT">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_FASTDCT</h4>
-<pre>public static final&nbsp;int FLAG_FASTDCT</pre>
-<div class="block">Use the fastest DCT/IDCT algorithm available in the underlying codec.  The
- default if this flag is not specified is implementation-specific.  For
- example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
- algorithm by default when compressing, because this has been shown to have
- only a very slight effect on accuracy, but it uses the accurate algorithm
- when decompressing, because this has been shown to have a larger effect.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FASTDCT">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_FASTDCT</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTDCT"><code>PARAM_FASTDCT</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_FASTDCT">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_ACCURATEDCT">
+<a id="FLAG_ACCURATEDCT">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_ACCURATEDCT</h4>
-<pre>public static final&nbsp;int FLAG_ACCURATEDCT</pre>
-<div class="block">Use the most accurate DCT/IDCT algorithm available in the underlying
- codec.  The default if this flag is not specified is
- implementation-specific.  For example, the implementation of TurboJPEG for
- libjpeg[-turbo] uses the fast algorithm by default when compressing,
- because this has been shown to have only a very slight effect on accuracy,
- but it uses the accurate algorithm when decompressing, because this has
- been shown to have a larger effect.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_ACCURATEDCT">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_ACCURATEDCT</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_FASTDCT"><code>PARAM_FASTDCT</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_ACCURATEDCT">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_STOPONWARNING">
+<a id="FLAG_STOPONWARNING">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_STOPONWARNING</h4>
-<pre>public static final&nbsp;int FLAG_STOPONWARNING</pre>
-<div class="block">Immediately discontinue the current compression/decompression/transform
- operation if the underlying codec throws a warning (non-fatal error).  The
- default behavior is to allow the operation to complete unless a fatal
- error is encountered.
- <p>
- NOTE: due to the design of the TurboJPEG Java API, only certain methods
- (specifically, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor.decompress*()</code></a> methods
- with a void return type) will complete and leave the output image in a
- fully recoverable state after a non-fatal error occurs.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_STOPONWARNING">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_STOPONWARNING</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_STOPONWARNING"><code>PARAM_STOPONWARNING</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_STOPONWARNING">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_PROGRESSIVE">
+<a id="FLAG_PROGRESSIVE">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_PROGRESSIVE</h4>
-<pre>public static final&nbsp;int FLAG_PROGRESSIVE</pre>
-<div class="block">Use progressive entropy coding in JPEG images generated by compression and
- transform operations.  Progressive entropy coding will generally improve
- compression relative to baseline entropy coding (the default), but it will
- reduce compression and decompression performance considerably.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_PROGRESSIVE">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_PROGRESSIVE</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_PROGRESSIVE"><code>PARAM_PROGRESSIVE</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_PROGRESSIVE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="FLAG_LIMITSCANS">
+<a id="FLAG_LIMITSCANS">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>FLAG_LIMITSCANS</h4>
-<pre>public static final&nbsp;int FLAG_LIMITSCANS</pre>
-<div class="block">Limit the number of progressive JPEG scans that the decompression and
- transform operations will process.  If a progressive JPEG image contains
- an unreasonably large number of scans, then this flag will cause the
- decompression and transform operations to throw 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>.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_LIMITSCANS">Constant Field Values</a></dd></dl>
+<pre>@Deprecated
+public static final&nbsp;int FLAG_LIMITSCANS</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#PARAM_SCANLIMIT"><code>PARAM_SCANLIMIT</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.FLAG_LIMITSCANS">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="NUMERR">
+<a id="NUMERR">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -1045,288 +1967,385 @@ public static final&nbsp;int FLAG_FORCESSE3</pre>
 <h4>NUMERR</h4>
 <pre>public static final&nbsp;int NUMERR</pre>
 <div class="block">The number of error codes</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMERR">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.NUMERR">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="ERR_WARNING">
+<a id="ERR_WARNING">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>ERR_WARNING</h4>
 <pre>public static final&nbsp;int ERR_WARNING</pre>
-<div class="block">The error was non-fatal and recoverable, but the image may still be
- corrupt.
+<div class="block">The error was non-fatal and recoverable, but the destination image may
still be corrupt.
  <p>
  NOTE: due to the design of the TurboJPEG Java API, only certain methods
- (specifically, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor.decompress*()</code></a> methods
- with a void return type) will complete and leave the output image in a
- fully recoverable state after a non-fatal error occurs.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.ERR_WARNING">Constant Field Values</a></dd></dl>
+ (specifically, <a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor.decompress*()</code></a> methods
+ with a void return type) will complete and leave the destination image in
+ a fully recoverable state after a non-fatal error occurs.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.ERR_WARNING">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="ERR_FATAL">
+<a id="ERR_FATAL">
 <!--   -->
 </a>
-<ul class="blockListLast">
+<ul class="blockList">
 <li class="blockList">
 <h4>ERR_FATAL</h4>
 <pre>public static final&nbsp;int ERR_FATAL</pre>
 <div class="block">The error was fatal and non-recoverable.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.ERR_FATAL">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJ.ERR_FATAL">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
+<a id="UNSCALED">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>UNSCALED</h4>
+<pre>public static final&nbsp;<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a> UNSCALED</pre>
+<div class="block">A <a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJScalingFactor</code></a> instance that specifies a scaling factor of 1/1
+ (no scaling)</div>
+</li>
+</ul>
+<a id="UNCROPPED">
+<!--   -->
+</a>
+<ul class="blockListLast">
+<li class="blockList">
+<h4>UNCROPPED</h4>
+<pre>public static final&nbsp;java.awt.Rectangle UNCROPPED</pre>
+<div class="block">A <code>java.awt.Rectangle</code> instance that specifies no cropping</div>
 </li>
 </ul>
+</li>
+</ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="getMCUWidth(int)">
+<a id="getMCUWidth(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getMCUWidth</h4>
-<pre>public static&nbsp;int&nbsp;getMCUWidth(int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;getMCUWidth&#8203;(int&nbsp;subsamp)</pre>
 <div class="block">Returns the MCU block width for the given level of chrominance
  subsampling.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>subsamp</code> - the level of chrominance subsampling (one of
- <code>SAMP_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the MCU block width for the given level of chrominance
- subsampling.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>subsamp</code> - the level of chrominance subsampling (one of
+ <a href="#SAMP_444"><code>SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the MCU block width for the given level of chrominance
+ subsampling.</dd>
+</dl>
 </li>
 </ul>
-<a name="getMCUHeight(int)">
+<a id="getMCUHeight(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getMCUHeight</h4>
-<pre>public static&nbsp;int&nbsp;getMCUHeight(int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;getMCUHeight&#8203;(int&nbsp;subsamp)</pre>
 <div class="block">Returns the MCU block height for the given level of chrominance
  subsampling.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>subsamp</code> - the level of chrominance subsampling (one of
- <code>SAMP_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the MCU block height for the given level of chrominance
- subsampling.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>subsamp</code> - the level of chrominance subsampling (one of
+ <a href="#SAMP_444"><code>SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the MCU block height for the given level of chrominance
+ subsampling.</dd>
+</dl>
 </li>
 </ul>
-<a name="getPixelSize(int)">
+<a id="getPixelSize(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getPixelSize</h4>
-<pre>public static&nbsp;int&nbsp;getPixelSize(int&nbsp;pixelFormat)</pre>
-<div class="block">Returns the pixel size (in bytes) for the given pixel format.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pixelFormat</code> - the pixel format (one of <code>PF_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the pixel size (in bytes) for the given pixel format.</dd></dl>
+<pre class="methodSignature">public static&nbsp;int&nbsp;getPixelSize&#8203;(int&nbsp;pixelFormat)</pre>
+<div class="block">Returns the pixel size (in samples) for the given pixel format.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pixelFormat</code> - the pixel format (one of <a href="#PF_RGB"><code>PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the pixel size (in samples) for the given pixel format.</dd>
+</dl>
 </li>
 </ul>
-<a name="getRedOffset(int)">
+<a id="getRedOffset(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getRedOffset</h4>
-<pre>public static&nbsp;int&nbsp;getRedOffset(int&nbsp;pixelFormat)</pre>
-<div class="block">For the given pixel format, returns the number of bytes that the red
- component is offset from the start of the pixel.  For instance, if a pixel
- of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
- then the red component will be
+<pre class="methodSignature">public static&nbsp;int&nbsp;getRedOffset&#8203;(int&nbsp;pixelFormat)</pre>
+<div class="block">For the given pixel format, returns the number of samples that the red
+ component is offset from the start of the pixel.  For instance, if an
+ 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
<code>char pixel[]</code>, then the red component will be
  <code>pixel[TJ.getRedOffset(TJ.PF_BGRX)]</code>.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pixelFormat</code> - the pixel format (one of <code>PF_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the red offset for the given pixel format, or -1 if the pixel
- format does not have a red component.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pixelFormat</code> - the pixel format (one of <a href="#PF_RGB"><code>PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the red offset for the given pixel format, or -1 if the pixel
+ format does not have a red component.</dd>
+</dl>
 </li>
 </ul>
-<a name="getGreenOffset(int)">
+<a id="getGreenOffset(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getGreenOffset</h4>
-<pre>public static&nbsp;int&nbsp;getGreenOffset(int&nbsp;pixelFormat)</pre>
-<div class="block">For the given pixel format, returns the number of bytes that the green
- component is offset from the start of the pixel.  For instance, if a pixel
- of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
- then the green component will be
+<pre class="methodSignature">public static&nbsp;int&nbsp;getGreenOffset&#8203;(int&nbsp;pixelFormat)</pre>
+<div class="block">For the given pixel format, returns the number of samples that the green
+ component is offset from the start of the pixel.  For instance, if an
+ 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
<code>char pixel[]</code>, then the green component will be
  <code>pixel[TJ.getGreenOffset(TJ.PF_BGRX)]</code>.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pixelFormat</code> - the pixel format (one of <code>PF_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the green offset for the given pixel format, or -1 if the pixel
- format does not have a green component.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pixelFormat</code> - the pixel format (one of <a href="#PF_RGB"><code>PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the green offset for the given pixel format, or -1 if the pixel
+ format does not have a green component.</dd>
+</dl>
 </li>
 </ul>
-<a name="getBlueOffset(int)">
+<a id="getBlueOffset(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getBlueOffset</h4>
-<pre>public static&nbsp;int&nbsp;getBlueOffset(int&nbsp;pixelFormat)</pre>
-<div class="block">For the given pixel format, returns the number of bytes that the blue
- component is offset from the start of the pixel.  For instance, if a pixel
- of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
- then the blue component will be
+<pre class="methodSignature">public static&nbsp;int&nbsp;getBlueOffset&#8203;(int&nbsp;pixelFormat)</pre>
+<div class="block">For the given pixel format, returns the number of samples that the blue
+ component is offset from the start of the pixel.  For instance, if an
+ 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
<code>char pixel[]</code>, then the blue component will be
  <code>pixel[TJ.getBlueOffset(TJ.PF_BGRX)]</code>.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pixelFormat</code> - the pixel format (one of <code>PF_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the blue offset for the given pixel format, or -1 if the pixel
- format does not have a blue component.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pixelFormat</code> - the pixel format (one of <a href="#PF_RGB"><code>PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the blue offset for the given pixel format, or -1 if the pixel
+ format does not have a blue component.</dd>
+</dl>
 </li>
 </ul>
-<a name="getAlphaOffset(int)">
+<a id="getAlphaOffset(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getAlphaOffset</h4>
-<pre>public static&nbsp;int&nbsp;getAlphaOffset(int&nbsp;pixelFormat)</pre>
-<div class="block">For the given pixel format, returns the number of bytes that the alpha
- component is offset from the start of the pixel.  For instance, if a pixel
- of format <code>TJ.PF_BGRA</code> is stored in <code>char pixel[]</code>,
- then the alpha component will be
+<pre class="methodSignature">public static&nbsp;int&nbsp;getAlphaOffset&#8203;(int&nbsp;pixelFormat)</pre>
+<div class="block">For the given pixel format, returns the number of samples that the alpha
+ component is offset from the start of the pixel.  For instance, if an
+ 8-bit-per-sample pixel of format <code>TJ.PF_BGRA</code> is stored in
<code>char pixel[]</code>, then the alpha component will be
  <code>pixel[TJ.getAlphaOffset(TJ.PF_BGRA)]</code>.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pixelFormat</code> - the pixel format (one of <code>PF_*</code>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the alpha offset for the given pixel format, or -1 if the pixel
- format does not have a alpha component.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pixelFormat</code> - the pixel format (one of <a href="#PF_RGB"><code>PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the alpha offset for the given pixel format, or -1 if the pixel
+ format does not have a alpha component.</dd>
+</dl>
 </li>
 </ul>
-<a name="bufSize(int, int, int)">
+<a id="bufSize(int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>bufSize</h4>
-<pre>public static&nbsp;int&nbsp;bufSize(int&nbsp;width,
-          int&nbsp;height,
-          int&nbsp;jpegSubsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;bufSize&#8203;(int&nbsp;width,
+                          int&nbsp;height,
+                          int&nbsp;jpegSubsamp)</pre>
 <div class="block">Returns the maximum size of the buffer (in bytes) required to hold a JPEG
  image with the given width, height, and level of chrominance subsampling.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>width</code> - the width (in pixels) of the JPEG image</dd><dd><code>height</code> - the height (in pixels) of the JPEG image</dd><dd><code>jpegSubsamp</code> - the level of chrominance subsampling to be used when
- generating the JPEG image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.SAMP_*</code></a>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the maximum size of the buffer (in bytes) required to hold a JPEG
- image with the given width, height, and level of chrominance subsampling.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>width</code> - the width (in pixels) of the JPEG image</dd>
+<dd><code>height</code> - the height (in pixels) of the JPEG image</dd>
+<dd><code>jpegSubsamp</code> - the level of chrominance subsampling to be used when
+ generating the JPEG image (one of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a>.)
+ <a href="#SAMP_UNKNOWN"><code>SAMP_UNKNOWN</code></a> is treated like <a href="#SAMP_444"><code>SAMP_444</code></a>, 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 <a href="#SAMP_444"><code>SAMP_444</code></a>.</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the maximum size of the buffer (in bytes) required to hold a JPEG
+ image with the given width, height, and level of chrominance subsampling.</dd>
+</dl>
 </li>
 </ul>
-<a name="bufSizeYUV(int, int, int, int)">
+<a id="bufSizeYUV(int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>bufSizeYUV</h4>
-<pre>public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
-             int&nbsp;pad,
-             int&nbsp;height,
-             int&nbsp;subsamp)</pre>
-<div class="block">Returns the size of the buffer (in bytes) required to hold a YUV planar
- image with the given width, height, and level of chrominance subsampling.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>width</code> - the width (in pixels) of the YUV image</dd><dd><code>pad</code> - the width of each line in each plane of the image is padded to
- the nearest multiple of this number of bytes (must be a power of 2.)</dd><dd><code>height</code> - the height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.SAMP_*</code></a>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the size of the buffer (in bytes) required to hold a YUV planar
- image with the given width, height, and level of chrominance subsampling.</dd></dl>
-</li>
-</ul>
-<a name="bufSizeYUV(int, int, int)">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>bufSizeYUV</h4>
-<pre>@Deprecated
-public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
-                        int&nbsp;height,
-                        int&nbsp;subsamp)</pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>bufSizeYUV(int, int, int, int)</code></a> instead.</i></div>
+<pre class="methodSignature">public static&nbsp;int&nbsp;bufSizeYUV&#8203;(int&nbsp;width,
+                             int&nbsp;align,
+                             int&nbsp;height,
+                             int&nbsp;subsamp)</pre>
+<div class="block">Returns the size of the buffer (in bytes) required to hold a unified
+ planar YUV image with the given width, height, and level of chrominance
+ subsampling.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>width</code> - the width (in pixels) of the YUV image</dd>
+<dd><code>align</code> - row alignment (in bytes) of the YUV image (must be a power of
+ 2.)  Setting this parameter to n specifies that each row in each plane of
+ the YUV image will be padded to the nearest multiple of n bytes
+ (1 = unpadded.)</dd>
+<dd><code>height</code> - the height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the size of the buffer (in bytes) required to hold a unified
+ planar YUV image with the given width, height, and level of chrominance
+ subsampling.</dd>
+</dl>
 </li>
 </ul>
-<a name="planeSizeYUV(int, int, int, int, int)">
+<a id="planeSizeYUV(int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>planeSizeYUV</h4>
-<pre>public static&nbsp;int&nbsp;planeSizeYUV(int&nbsp;componentID,
-               int&nbsp;width,
-               int&nbsp;stride,
-               int&nbsp;height,
-               int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;planeSizeYUV&#8203;(int&nbsp;componentID,
+                               int&nbsp;width,
+                               int&nbsp;stride,
+                               int&nbsp;height,
+                               int&nbsp;subsamp)</pre>
 <div class="block">Returns the size of the buffer (in bytes) required to hold a YUV image
  plane with the given parameters.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
- 2 = V/Cr)</dd><dd><code>width</code> - width (in pixels) of the YUV image.  NOTE: this is the width
- of the whole image, not the plane width.</dd><dd><code>stride</code> - bytes per line in the image plane.</dd><dd><code>height</code> - height (in pixels) of the YUV image.  NOTE: this is the
- height of the whole image, not the plane height.</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.SAMP_*</code></a>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the size of the buffer (in bytes) required to hold a YUV planar
- image with the given parameters.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
+ 2 = V/Cr)</dd>
+<dd><code>width</code> - width (in pixels) of the YUV image.  NOTE: this is the width
+ of the whole image, not the plane width.</dd>
+<dd><code>stride</code> - bytes per row in the image plane.</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image.  NOTE: this is the
+ height of the whole image, not the plane height.</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the size of the buffer (in bytes) required to hold a YUV image
+ plane with the given parameters.</dd>
+</dl>
 </li>
 </ul>
-<a name="planeWidth(int, int, int)">
+<a id="planeWidth(int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>planeWidth</h4>
-<pre>public static&nbsp;int&nbsp;planeWidth(int&nbsp;componentID,
-             int&nbsp;width,
-             int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;planeWidth&#8203;(int&nbsp;componentID,
+                             int&nbsp;width,
+                             int&nbsp;subsamp)</pre>
 <div class="block">Returns the plane width of a YUV image plane with the given parameters.
- Refer to <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> for a description of plane width.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
- 2 = V/Cr)</dd><dd><code>width</code> - width (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV image
- (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.SAMP_*</code></a>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the plane width of a YUV image plane with the given parameters.</dd></dl>
+ Refer to <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> for a description of plane width.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
+ 2 = V/Cr)</dd>
+<dd><code>width</code> - width (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV image
+ (one of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the plane width of a YUV image plane with the given parameters.</dd>
+</dl>
 </li>
 </ul>
-<a name="planeHeight(int, int, int)">
+<a id="planeHeight(int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>planeHeight</h4>
-<pre>public static&nbsp;int&nbsp;planeHeight(int&nbsp;componentID,
-              int&nbsp;height,
-              int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public static&nbsp;int&nbsp;planeHeight&#8203;(int&nbsp;componentID,
+                              int&nbsp;height,
+                              int&nbsp;subsamp)</pre>
 <div class="block">Returns the plane height of a YUV image plane with the given parameters.
- Refer to <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> for a description of plane height.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
- 2 = V/Cr)</dd><dd><code>height</code> - height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV image
- (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.SAMP_*</code></a>)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the plane height of a YUV image plane with the given parameters.</dd></dl>
+ Refer to <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> for a description of plane height.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>componentID</code> - ID number of the image plane (0 = Y, 1 = U/Cb,
+ 2 = V/Cr)</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV image
+ (one of <a href="#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the plane height of a YUV image plane with the given parameters.</dd>
+</dl>
 </li>
 </ul>
-<a name="getScalingFactors()">
+<a id="getScalingFactors()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getScalingFactors</h4>
-<pre>public static&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>[]&nbsp;getScalingFactors()</pre>
-<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor in
- this implementation of TurboJPEG supports.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>a list of fractional scaling factors that the JPEG decompressor in
- this implementation of TurboJPEG supports.</dd></dl>
+<pre class="methodSignature">public static&nbsp;<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>[]&nbsp;getScalingFactors()</pre>
+<div class="block">Returns a list of fractional scaling factors that the JPEG decompressor
+ supports.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a list of fractional scaling factors that the JPEG decompressor
+ supports.</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -1335,16 +2354,8 @@ public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev Class</li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJ.html" target="_top">Frames</a></li>
-<li><a href="TJ.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -1357,25 +2368,30 @@ public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index a53f879..a6e6dfc 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJCompressor</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10,"i1":10,"i2":10,"i3":42,"i4":42,"i5":10,"i6":10,"i7":42,"i8":42,"i9":10,"i10":42,"i11":10,"i12":10,"i13":10,"i14":10,"i15":42,"i16":10,"i17":10,"i18":10,"i19":10,"i20":10,"i21":42};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJCompressor.html" target="_top">Frames</a></li>
-<li><a href="TJCompressor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJCompressor" class="title">Class TJCompressor</h2>
 </div>
 <div class="contentContainer">
 <li class="blockList">
 <dl>
 <dt>All Implemented Interfaces:</dt>
-<dd>java.io.Closeable, java.lang.AutoCloseable</dd>
+<dd><code>java.io.Closeable</code>, <code>java.lang.AutoCloseable</code></dd>
 </dl>
 <hr>
-<br>
-<pre>public class <span class="strong">TJCompressor</span>
+<pre>public class <span class="typeNameLabel">TJCompressor</span>
 extends java.lang.Object
 implements java.io.Closeable</pre>
 <div class="block">TurboJPEG compressor</div>
@@ -111,254 +145,283 @@ implements java.io.Closeable</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor()">TJCompressor</a></strong>()</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">TJCompressor</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG compressor instance.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)">TJCompressor</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D,int,int,int,int,int,int)">TJCompressor</a></span>&#8203;(byte[]&nbsp;srcImage,
             int&nbsp;x,
             int&nbsp;y,
             int&nbsp;width,
-            int&nbsp;height)</code>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
-</td>
-</tr>
-<tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int)">TJCompressor</a></strong>(byte[]&nbsp;srcImage,
-            int&nbsp;width,
             int&nbsp;pitch,
             int&nbsp;height,
-            int&nbsp;pixelFormat)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-</div>
+            int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
+ created instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)">TJCompressor</a></strong>(byte[]&nbsp;srcImage,
+<tr class="altColor">
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.awt.image.BufferedImage,int,int,int,int)">TJCompressor</a></span>&#8203;(java.awt.image.BufferedImage&nbsp;srcImage,
             int&nbsp;x,
             int&nbsp;y,
             int&nbsp;width,
-            int&nbsp;pitch,
-            int&nbsp;height,
-            int&nbsp;pixelFormat)</code>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
+            int&nbsp;height)</code></th>
+<td class="colLast">
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
+ created instance.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t6" class="tableTab"><span><a href="javascript:show(32);">Deprecated Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#close()">close</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#close()">close</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Free the native structures associated with this compressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20byte[],%20int)">compress</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
-        byte[]&nbsp;dstBuf,
-        int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)"><code>compress(byte[], int)</code></a> instead.</i></div>
-</div>
-</td>
-</tr>
-<tr class="altColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(java.awt.image.BufferedImage,%20int)">compress</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
-        int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)"><code>compress(int)</code></a> instead.</i></div>
-</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#compress()">compress</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
+ compressor instance and return a buffer containing a JPEG image.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i2" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)">compress</a></strong>(byte[]&nbsp;dstBuf,
-        int&nbsp;flags)</code>
-<div class="block">Compress the uncompressed source image associated with this compressor
- instance and output a JPEG image to the given destination buffer.</div>
-</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)">compress</a></strong>(int&nbsp;flags)</code>
-<div class="block">Compress the uncompressed source image associated with this compressor
- instance and return a buffer containing a JPEG image.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#compress(byte%5B%5D)">compress</a></span>&#8203;(byte[]&nbsp;dstBuf)</code></th>
+<td class="colLast">
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
+ compressor instance and output a JPEG image to the given destination
+ buffer.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i3" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20byte[],%20int)">encodeYUV</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
-         byte[]&nbsp;dstBuf,
-         int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)"><code>encodeYUV(byte[], int)</code></a> instead.</i></div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#compress(byte%5B%5D,int)">compress</a></span>&#8203;(byte[]&nbsp;dstBuf,
+        int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#compress(byte%5B%5D)"><code>compress(byte[])</code></a> instead.</div>
 </div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i4" class="altColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(java.awt.image.BufferedImage,%20int)">encodeYUV</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
-         int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>encodeYUV(int, int)</code></a> instead.</i></div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#compress(int)">compress</a></span>&#8203;(int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#compress()"><code>compress()</code></a> instead.</div>
 </div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)">encodeYUV</a></strong>(byte[]&nbsp;dstBuf,
-         int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>encodeYUV(YUVImage, int)</code></a> instead.</i></div>
-</div>
+<tr id="i5" class="rowColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(int)">encodeYUV</a></span>&#8203;(int&nbsp;align)</code></th>
+<td class="colLast">
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample unified planar YUV image and
+ return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded image.</div>
 </td>
 </tr>
-<tr class="altColor">
-<td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int)">encodeYUV</a></strong>(int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>encodeYUV(int, int)</code></a> instead.</i></div>
+<tr id="i6" class="altColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(int%5B%5D)">encodeYUV</a></span>&#8203;(int[]&nbsp;strides)</code></th>
+<td class="colLast">
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into separate 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded
+ image planes.</div>
+</td>
+</tr>
+<tr id="i7" class="rowColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(int%5B%5D,int)">encodeYUV</a></span>&#8203;(int[]&nbsp;strides,
+         int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(int%5B%5D)"><code>encodeYUV(int[])</code></a> instead.</div>
 </div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int[],%20int)">encodeYUV</a></strong>(int[]&nbsp;strides,
-         int&nbsp;flags)</code>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into separate Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the encoded image planes.</div>
+<tr id="i8" class="altColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(int,int)">encodeYUV</a></span>&#8203;(int&nbsp;align,
+         int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(int)"><code>encodeYUV(int)</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)">encodeYUV</a></strong>(int&nbsp;pad,
-         int&nbsp;flags)</code>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a unified YUV planar image buffer and return a
<code>YUVImage</code> instance containing the encoded image.</div>
+<tr id="i9" class="rowColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)">encodeYUV</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage)</code></th>
+<td class="colLast">
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample planar YUV image and store it
in the given <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i10" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)">encodeYUV</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
-         int&nbsp;flags)</code>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a YUV planar image and store it in the given
- <code>YUVImage</code> instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">encodeYUV</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
+         int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>encodeYUV(YUVImage)</code></a>
+ instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i11" class="rowColor">
 <td class="colFirst"><code>protected void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#finalize()">finalize</a></strong>()</code>&nbsp;</td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#finalize()">finalize</a></span>()</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
-<tr class="rowColor">
+<tr id="i12" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#getCompressedSize()">getCompressedSize</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#get(int)">get</a></span>&#8203;(int&nbsp;param)</code></th>
+<td class="colLast">
+<div class="block">Get the value of a compression parameter.</div>
+</td>
+</tr>
+<tr id="i13" class="rowColor">
+<td class="colFirst"><code>int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getCompressedSize()">getCompressedSize</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the size of the image (in bytes) generated by the most recent
  compress operation.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i14" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setJPEGQuality(int)">setJPEGQuality</a></strong>(int&nbsp;quality)</code>
-<div class="block">Set the JPEG image quality level for subsequent compress operations.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#set(int,int)">set</a></span>&#8203;(int&nbsp;param,
+   int&nbsp;value)</code></th>
+<td class="colLast">
+<div class="block">Set the value of a compression parameter.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i15" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)">setSourceImage</a></strong>(java.awt.image.BufferedImage&nbsp;srcImage,
-              int&nbsp;x,
-              int&nbsp;y,
-              int&nbsp;width,
-              int&nbsp;height)</code>
-<div class="block">Associate an uncompressed RGB or grayscale source image with this
- compressor instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setJPEGQuality(int)">setJPEGQuality</a></span>&#8203;(int&nbsp;quality)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="#set(int,int)"><code>set</code></a>(<a href="TJ.html#PARAM_QUALITY"><code>TJ.PARAM_QUALITY</code></a>, ...)</code> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i16" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int)">setSourceImage</a></strong>(byte[]&nbsp;srcImage,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)">setSourceImage</a></span>&#8203;(byte[]&nbsp;srcImage,
+              int&nbsp;x,
+              int&nbsp;y,
               int&nbsp;width,
               int&nbsp;pitch,
               int&nbsp;height,
-              int&nbsp;pixelFormat)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-</div>
+              int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Associate an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i17" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)">setSourceImage</a></strong>(byte[]&nbsp;srcImage,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)">setSourceImage</a></span>&#8203;(java.awt.image.BufferedImage&nbsp;srcImage,
               int&nbsp;x,
               int&nbsp;y,
               int&nbsp;width,
-              int&nbsp;pitch,
-              int&nbsp;height,
-              int&nbsp;pixelFormat)</code>
-<div class="block">Associate an uncompressed RGB, grayscale, or CMYK source image with this
- compressor instance.</div>
+              int&nbsp;height)</code></th>
+<td class="colLast">
+<div class="block">Associate an 8-bit-per-pixel packed-pixel RGB or grayscale source image
+ with this compressor instance.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i18" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</code>
-<div class="block">Associate an uncompressed YUV planar source image with this compressor
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</code></th>
+<td class="colLast">
+<div class="block">Associate an 8-bit-per-sample planar YUV source image with this compressor
  instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i19" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSubsamp(int)">setSubsamp</a></strong>(int&nbsp;newSubsamp)</code>
-<div class="block">Set the level of chrominance subsampling for subsequent compress/encode
- operations.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage12(short%5B%5D,int,int,int,int,int,int)">setSourceImage12</a></span>&#8203;(short[]&nbsp;srcImage,
+                int&nbsp;x,
+                int&nbsp;y,
+                int&nbsp;width,
+                int&nbsp;pitch,
+                int&nbsp;height,
+                int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Associate a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+</td>
+</tr>
+<tr id="i20" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage16(short%5B%5D,int,int,int,int,int,int)">setSourceImage16</a></span>&#8203;(short[]&nbsp;srcImage,
+                int&nbsp;x,
+                int&nbsp;y,
+                int&nbsp;width,
+                int&nbsp;pitch,
+                int&nbsp;height,
+                int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Associate a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+</td>
+</tr>
+<tr id="i21" class="rowColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSubsamp(int)">setSubsamp</a></span>&#8203;(int&nbsp;subsamp)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="#set(int,int)"><code>set</code></a>(<a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>, ...)</code> instead.</div>
+</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -366,6 +429,7 @@ implements java.io.Closeable</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -373,505 +437,643 @@ implements java.io.Closeable</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="TJCompressor()">
+<a id="&lt;init&gt;()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJCompressor</h4>
 <pre>public&nbsp;TJCompressor()
-             throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+             throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Create a TurboJPEG compressor instance.</div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
-</li>
-</ul>
-<a name="TJCompressor(byte[], int, int, int, int, int, int)">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>TJCompressor</h4>
-<pre>public&nbsp;TJCompressor(byte[]&nbsp;srcImage,
-            int&nbsp;x,
-            int&nbsp;y,
-            int&nbsp;width,
-            int&nbsp;pitch,
-            int&nbsp;height,
-            int&nbsp;pixelFormat)
-             throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>x</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>y</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>width</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>pitch</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>height</code> - see <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd><dd><code>pixelFormat</code> - pixel format of the source image (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="TJCompressor(byte[], int, int, int, int)">
+<a id="&lt;init&gt;(byte[],int,int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJCompressor</h4>
-<pre>@Deprecated
-public&nbsp;TJCompressor(byte[]&nbsp;srcImage,
-                       int&nbsp;width,
-                       int&nbsp;pitch,
-                       int&nbsp;height,
-                       int&nbsp;pixelFormat)
-             throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>TJCompressor(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre>public&nbsp;TJCompressor&#8203;(byte[]&nbsp;srcImage,
+                    int&nbsp;x,
+                    int&nbsp;y,
+                    int&nbsp;width,
+                    int&nbsp;pitch,
+                    int&nbsp;height,
+                    int&nbsp;pixelFormat)
+             throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
+ created instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>x</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>y</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>width</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>pitch</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>height</code> - see <a href="#setSourceImage(byte%5B%5D,int,int,int,int,int,int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> for description</dd>
+<dd><code>pixelFormat</code> - pixel format of the source image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="TJCompressor(java.awt.image.BufferedImage, int, int, int, int)">
+<a id="&lt;init&gt;(java.awt.image.BufferedImage,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>TJCompressor</h4>
-<pre>public&nbsp;TJCompressor(java.awt.image.BufferedImage&nbsp;srcImage,
-            int&nbsp;x,
-            int&nbsp;y,
-            int&nbsp;width,
-            int&nbsp;height)
-             throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG compressor instance and associate the uncompressed
- source image stored in <code>srcImage</code> with the newly created
- instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd><dd><code>x</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd><dd><code>y</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd><dd><code>width</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd><dd><code>height</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre>public&nbsp;TJCompressor&#8203;(java.awt.image.BufferedImage&nbsp;srcImage,
+                    int&nbsp;x,
+                    int&nbsp;y,
+                    int&nbsp;width,
+                    int&nbsp;height)
+             throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+ packed-pixel source image stored in <code>srcImage</code> with the newly
+ created instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - see
+ <a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
+<dd><code>x</code> - see
+ <a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
+<dd><code>y</code> - see
+ <a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
+<dd><code>width</code> - see
+ <a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
+<dd><code>height</code> - see
+ <a href="#setSourceImage(java.awt.image.BufferedImage,int,int,int,int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> for description</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="setSourceImage(byte[], int, int, int, int, int, int)">
+<a id="setSourceImage(byte[],int,int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>setSourceImage</h4>
-<pre>public&nbsp;void&nbsp;setSourceImage(byte[]&nbsp;srcImage,
-                  int&nbsp;x,
-                  int&nbsp;y,
-                  int&nbsp;width,
-                  int&nbsp;pitch,
-                  int&nbsp;height,
-                  int&nbsp;pixelFormat)
-                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Associate an uncompressed RGB, grayscale, or CMYK source image with this
- compressor instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - image buffer containing RGB, grayscale, or CMYK pixels to
- be compressed or encoded.  This buffer is not modified.</dd><dd><code>x</code> - x offset (in pixels) of the region in the source image from which
- the JPEG or YUV image should be compressed/encoded</dd><dd><code>y</code> - y offset (in pixels) of the region in the source image from which
- the JPEG or YUV image should be compressed/encoded</dd><dd><code>width</code> - width (in pixels) of the region in the source image from
- which the JPEG or YUV image should be compressed/encoded</dd><dd><code>pitch</code> - bytes per line of the source image.  Normally, this should be
- <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
- unpadded, but you can use this parameter to, for instance, specify that
- the scanlines in the source image are padded to a 4-byte boundary or to
- compress/encode a JPEG or YUV image from a region of a larger source
- image.  You can also be clever and use this parameter to skip lines, etc.
- Setting this parameter to 0 is the equivalent of setting it to
- <code>width * TJ.pixelSize(pixelFormat)</code>.</dd><dd><code>height</code> - height (in pixels) of the region in the source image from
- which the JPEG or YUV image should be compressed/encoded</dd><dd><code>pixelFormat</code> - pixel format of the source image (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
-</li>
-</ul>
-<a name="setSourceImage(byte[], int, int, int, int)">
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage&#8203;(byte[]&nbsp;srcImage,
+                           int&nbsp;x,
+                           int&nbsp;y,
+                           int&nbsp;width,
+                           int&nbsp;pitch,
+                           int&nbsp;height,
+                           int&nbsp;pixelFormat)
+                    throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - buffer containing a packed-pixel RGB, grayscale, or CMYK
+ source image to be compressed or encoded.  This buffer is not modified.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the source image from which
+ the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the source image from which
+ the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>width</code> - width (in pixels) of the region in the source image from
+ which the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>pitch</code> - bytes per row in the source image.  Normally this should be
+ <code>width * <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>,
+ if the source image is unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>width *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  However,
+ you can also use this parameter to specify the row alignment/padding of
+ the source image, to skip rows, or to compress/encode a JPEG or YUV image
+ from a specific region of a larger source image.</dd>
+<dd><code>height</code> - height (in pixels) of the region in the source image from
+ which the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>pixelFormat</code> - pixel format of the source image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="setSourceImage12(short[],int,int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setSourceImage</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;setSourceImage(byte[]&nbsp;srcImage,
+<h4>setSourceImage12</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage12&#8203;(short[]&nbsp;srcImage,
+                             int&nbsp;x,
+                             int&nbsp;y,
                              int&nbsp;width,
                              int&nbsp;pitch,
                              int&nbsp;height,
                              int&nbsp;pixelFormat)
-                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[],%20int,%20int,%20int,%20int,%20int,%20int)"><code>setSourceImage(byte[], int, int, int, int, int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+                      throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.  Note that 12-bit-per-sample
+ packed-pixel source images can only be compressed into 12-bit-per-sample
+ JPEG images.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - buffer containing a packed-pixel RGB, grayscale, or CMYK
+ source image to be compressed.  This buffer is not modified.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the source image from which
+ the JPEG image should be compressed</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the source image from which
+ the JPEG image should be compressed</dd>
+<dd><code>width</code> - width (in pixels) of the region in the source image from
+ which the JPEG image should be compressed</dd>
+<dd><code>pitch</code> - samples per row in the source image.  Normally this should be
+ <code>width * <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>,
+ if the source image is unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>width *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  However,
+ you can also use this parameter to specify the row alignment/padding of
+ the source image, to skip rows, or to compress a JPEG image from a
+ specific region of a larger source image.</dd>
+<dd><code>height</code> - height (in pixels) of the region in the source image from
+ which the JPEG image should be compressed</dd>
+<dd><code>pixelFormat</code> - pixel format of the source image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="setSourceImage(java.awt.image.BufferedImage, int, int, int, int)">
+<a id="setSourceImage16(short[],int,int,int,int,int,int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>setSourceImage16</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage16&#8203;(short[]&nbsp;srcImage,
+                             int&nbsp;x,
+                             int&nbsp;y,
+                             int&nbsp;width,
+                             int&nbsp;pitch,
+                             int&nbsp;height,
+                             int&nbsp;pixelFormat)
+                      throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+ image with this compressor instance.  Note that 16-bit-per-sample
+ packed-pixel source images can only be compressed into 16-bit-per-sample
+ lossless JPEG images.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - buffer containing a packed-pixel RGB, grayscale, or CMYK
+ source image to be compressed.  This buffer is not modified.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the source image from which
+ the JPEG image should be compressed</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the source image from which
+ the JPEG image should be compressed</dd>
+<dd><code>width</code> - width (in pixels) of the region in the source image from
+ which the JPEG image should be compressed</dd>
+<dd><code>pitch</code> - samples per row in the source image.  Normally this should be
+ <code>width * <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>,
+ if the source image is unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>width *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  However,
+ you can also use this parameter to specify the row alignment/padding of
+ the source image, to skip rows, or to compress a JPEG image from a
+ specific region of a larger source image.</dd>
+<dd><code>height</code> - height (in pixels) of the region in the source image from
+ which the JPEG image should be compressed</dd>
+<dd><code>pixelFormat</code> - pixel format of the source image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="setSourceImage(java.awt.image.BufferedImage,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>setSourceImage</h4>
-<pre>public&nbsp;void&nbsp;setSourceImage(java.awt.image.BufferedImage&nbsp;srcImage,
-                  int&nbsp;x,
-                  int&nbsp;y,
-                  int&nbsp;width,
-                  int&nbsp;height)
-                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Associate an uncompressed RGB or grayscale source image with this
- compressor instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - a <code>BufferedImage</code> instance containing RGB or
- grayscale pixels to be compressed or encoded.  This image is not modified.</dd><dd><code>x</code> - x offset (in pixels) of the region in the source image from which
- the JPEG or YUV image should be compressed/encoded</dd><dd><code>y</code> - y offset (in pixels) of the region in the source image from which
- the JPEG or YUV image should be compressed/encoded</dd><dd><code>width</code> - width (in pixels) of the region in the source image from
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage&#8203;(java.awt.image.BufferedImage&nbsp;srcImage,
+                           int&nbsp;x,
+                           int&nbsp;y,
+                           int&nbsp;width,
+                           int&nbsp;height)
+                    throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate an 8-bit-per-pixel packed-pixel RGB or grayscale source image
+ with this compressor instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - a <code>BufferedImage</code> instance containing a
+ packed-pixel RGB or grayscale source image to be compressed or encoded.
+ This image is not modified.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the source image from which
+ the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the source image from which
+ the JPEG or YUV image should be compressed/encoded</dd>
+<dd><code>width</code> - width (in pixels) of the region in the source image from
  which the JPEG or YUV image should be compressed/encoded (0 = use the
- width of the source image)</dd><dd><code>height</code> - height (in pixels) of the region in the source image from
+ width of the source image)</dd>
+<dd><code>height</code> - height (in pixels) of the region in the source image from
  which the JPEG or YUV image should be compressed/encoded (0 = use the
  height of the source image)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">
+<a id="setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>setSourceImage</h4>
-<pre>public&nbsp;void&nbsp;setSourceImage(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)
-                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Associate an uncompressed YUV planar source image with this compressor
- instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - YUV planar image to be compressed.  This image is not
- modified.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)
+                    throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate an 8-bit-per-sample planar YUV source image with this compressor
+ instance.  This method sets <a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a> to the chrominance
+ subsampling level of the source image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - planar YUV source image to be compressed.  This image is
+ not modified.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="setSubsamp(int)">
+<a id="set(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setSubsamp</h4>
-<pre>public&nbsp;void&nbsp;setSubsamp(int&nbsp;newSubsamp)</pre>
-<div class="block">Set the level of chrominance subsampling for subsequent compress/encode
- operations.  When pixels are converted from RGB to YCbCr (see
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr"><code>TJ.CS_YCbCr</code></a>) or from CMYK to YCCK (see <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCCK"><code>TJ.CS_YCCK</code></a>) 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".
- <p>
- NOTE: This method has no effect when compressing a JPEG image from a YUV
- planar source.  In that case, the level of chrominance subsampling in
- the JPEG image is determined by the source.  Furthermore, this method has
- no effect when encoding to a pre-allocated <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.  In
- that case, the level of chrominance subsampling is determined by the
- destination.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>newSubsamp</code> - the level of chrominance subsampling to use in
- subsequent compress/encode oeprations (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
-</li>
-</ul>
-<a name="setJPEGQuality(int)">
+<h4>set</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;set&#8203;(int&nbsp;param,
+                int&nbsp;value)</pre>
+<div class="block">Set the value of a compression parameter.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>param</code> - one of <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_*</code></a></dd>
+<dd><code>value</code> - value of the compression parameter (refer to
+ <a href="TJ.html#PARAM_STOPONWARNING"><code>parameter documentation</code></a>)</dd>
+</dl>
+</li>
+</ul>
+<a id="get(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setJPEGQuality</h4>
-<pre>public&nbsp;void&nbsp;setJPEGQuality(int&nbsp;quality)</pre>
-<div class="block">Set the JPEG image quality level for subsequent compress operations.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>quality</code> - the new JPEG image quality level (1 to 100, 1 = worst,
- 100 = best)</dd></dl>
+<h4>get</h4>
+<pre class="methodSignature">public&nbsp;int&nbsp;get&#8203;(int&nbsp;param)</pre>
+<div class="block">Get the value of a compression parameter.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>param</code> - one of <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_*</code></a></dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the value of the specified compression parameter, or -1 if the
+ value is unknown.</dd>
+</dl>
 </li>
 </ul>
-<a name="compress(byte[], int)">
+<a id="setSubsamp(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>compress</h4>
-<pre>public&nbsp;void&nbsp;compress(byte[]&nbsp;dstBuf,
-            int&nbsp;flags)
-              throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Compress the uncompressed source image associated with this compressor
- instance and output a JPEG image to the given destination buffer.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstBuf</code> - buffer that will receive the JPEG image.  Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSize(int,%20int,%20int)"><code>TJ.bufSize(int, int, int)</code></a> to determine the maximum size for this buffer based on
- the source image's width and height and the desired level of chrominance
- subsampling.</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>setSubsamp</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;setSubsamp&#8203;(int&nbsp;subsamp)</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="#set(int,int)"><code>set</code></a>(<a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>, ...)</code> instead.</div>
+</div>
+</li>
+</ul>
+<a id="setJPEGQuality(int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>setJPEGQuality</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;setJPEGQuality&#8203;(int&nbsp;quality)</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use
+ <code><a href="#set(int,int)"><code>set</code></a>(<a href="TJ.html#PARAM_QUALITY"><code>TJ.PARAM_QUALITY</code></a>, ...)</code> instead.</div>
+</div>
 </li>
 </ul>
-<a name="compress(int)">
+<a id="compress(byte[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>compress</h4>
-<pre>public&nbsp;byte[]&nbsp;compress(int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Compress the uncompressed source image associated with this compressor
- instance and return a buffer containing a JPEG image.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a buffer containing a JPEG image.  The length of this buffer will
- not be equal to the size of the JPEG image.  Use <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#getCompressedSize()"><code>getCompressedSize()</code></a> to obtain the size of the JPEG image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;void&nbsp;compress&#8203;(byte[]&nbsp;dstBuf)
+              throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
+ compressor instance and output a JPEG image to the given destination
+ buffer.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBuf</code> - buffer that will receive the JPEG image.  Use
+ <a href="TJ.html#bufSize(int,int,int)"><code>TJ.bufSize()</code></a> to determine the maximum size for this
+ buffer based on the source image's width and height and the desired level
+ of chrominance subsampling (see <a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>.)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="compress(java.awt.image.BufferedImage, byte[], int)">
+<a id="compress(byte[],int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>compress</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;compress(java.awt.image.BufferedImage&nbsp;srcImage,
-                       byte[]&nbsp;dstBuf,
-                       int&nbsp;flags)
-              throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(byte[],%20int)"><code>compress(byte[], int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;compress&#8203;(byte[]&nbsp;dstBuf,
+                     int&nbsp;flags)
+              throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#compress(byte%5B%5D)"><code>compress(byte[])</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="compress(java.awt.image.BufferedImage, int)">
+<a id="compress()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>compress</h4>
-<pre>@Deprecated
-public&nbsp;byte[]&nbsp;compress(java.awt.image.BufferedImage&nbsp;srcImage,
-                         int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#compress(int)"><code>compress(int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;byte[]&nbsp;compress()
+                throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Compress the packed-pixel or planar YUV source image associated with this
+ compressor instance and return a buffer containing a JPEG image.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a buffer containing a JPEG image.  The length of this buffer will
+ not be equal to the size of the JPEG image.  Use
+ <a href="#getCompressedSize()"><code>getCompressedSize()</code></a> to obtain the size of the JPEG image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="encodeYUV(org.libjpegturbo.turbojpeg.YUVImage, int)">
+<a id="compress(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>encodeYUV</h4>
-<pre>public&nbsp;void&nbsp;encodeYUV(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
-             int&nbsp;flags)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a YUV planar image and store it in the given
- <code>YUVImage</code> instance.   This method uses the accelerated color
- conversion routines in TurboJPEG's underlying codec but does not execute
- any of the other steps in the JPEG compression process.  Encoding
- CMYK source images to YUV is not supported.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstImage</code> - <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance that will receive the YUV planar
- image</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>compress</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;byte[]&nbsp;compress&#8203;(int&nbsp;flags)
+                throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#compress()"><code>compress()</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="encodeYUV(byte[], int)">
+<a id="encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;encodeYUV(byte[]&nbsp;dstBuf,
-                        int&nbsp;flags)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>encodeYUV(YUVImage, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;void&nbsp;encodeYUV&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample planar YUV image and store it
+ in the given <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.  This method 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.
+ Encoding CMYK source images into YUV images is not supported.  This method
+ sets <a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a> to the chrominance subsampling level of the
+ destination image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstImage</code> - <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance that will receive the planar YUV
+ image</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="encodeYUV(int, int)">
+<a id="encodeYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV(int&nbsp;pad,
-                 int&nbsp;flags)
-                   throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into a unified YUV planar image buffer and return a
- <code>YUVImage</code> instance containing the encoded image.  This method
- uses the accelerated color conversion routines in TurboJPEG's underlying
- codec but does not execute any of the other steps in the JPEG compression
- process.  Encoding CMYK source images to YUV is not supported.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>pad</code> - the width of each line in each plane of the YUV image will be
- padded to the nearest multiple of this number of bytes (must be a power of
- 2.)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a YUV planar image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
-</li>
-</ul>
-<a name="encodeYUV(int[], int)">
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;encodeYUV&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
+                      int&nbsp;flags)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>encodeYUV(YUVImage)</code></a>
+ instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="encodeYUV(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV(int[]&nbsp;strides,
-                 int&nbsp;flags)
-                   throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Encode the uncompressed source image associated with this compressor
- instance into separate Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the encoded image planes.  This
method uses the accelerated color conversion routines in TurboJPEG's
- underlying codec but does not execute any of the other steps in the JPEG
compression process.  Encoding CMYK source images to YUV is not supported.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>strides</code> - an array of integers, each specifying the number of bytes
- per line in the corresponding plane of the output image.  Setting the
- stride for any plane to 0 is the same as setting it to the component width
- of the plane.  If <code>strides</code> is null, then the strides for all
- planes will be set to their respective component widths.  You can adjust
- the strides in order to add an arbitrary amount of line padding to each
- plane.</dd><dd><code>flags</code> - the bitwise OR of one or more of
<a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a YUV planar image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
-</li>
-</ul>
-<a name="encodeYUV(int)">
+<pre class="methodSignature">public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV&#8203;(int&nbsp;align)
+                   throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into an 8-bit-per-sample unified planar YUV image and
+ return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded image.  This
+ method 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.  Encoding CMYK source images into YUV
images is not supported.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>align</code> - 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.)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the unified planar YUV
encoded image</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="encodeYUV(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>@Deprecated
-public&nbsp;byte[]&nbsp;encodeYUV(int&nbsp;flags)
-                 throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>encodeYUV(int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">@Deprecated
+public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV&#8203;(int&nbsp;align,
+                          int&nbsp;flags)
+                   throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(int)"><code>encodeYUV(int)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="encodeYUV(java.awt.image.BufferedImage, byte[], int)">
+<a id="encodeYUV(int[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
-                        byte[]&nbsp;dstBuf,
-                        int&nbsp;flags)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(byte[],%20int)"><code>encodeYUV(byte[], int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV&#8203;(int[]&nbsp;strides)
+                   throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Encode the 8-bit-per-sample packed-pixel source image associated with this
+ compressor instance into separate 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded
+ image planes.  This method 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.  Encoding CMYK source images into
+ YUV images is not supported.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>strides</code> - 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 <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a>.)  If <code>strides</code> 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.</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the encoded image planes</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="encodeYUV(java.awt.image.BufferedImage, int)">
+<a id="encodeYUV(int[],int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>encodeYUV</h4>
-<pre>@Deprecated
-public&nbsp;byte[]&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
+<pre class="methodSignature">@Deprecated
+public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;encodeYUV&#8203;(int[]&nbsp;strides,
                           int&nbsp;flags)
-                 throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(java.awt.image.BufferedImage,%20int,%20int,%20int,%20int)"><code>setSourceImage(BufferedImage, int, int, int, int)</code></a> and
- <a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#encodeYUV(int,%20int)"><code>encodeYUV(int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+                   throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a> and <a href="#encodeYUV(int%5B%5D)"><code>encodeYUV(int[])</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getCompressedSize()">
+<a id="getCompressedSize()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getCompressedSize</h4>
-<pre>public&nbsp;int&nbsp;getCompressedSize()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getCompressedSize()</pre>
 <div class="block">Returns the size of the image (in bytes) generated by the most recent
  compress operation.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the size of the image (in bytes) generated by the most recent
- compress operation.</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the size of the image (in bytes) generated by the most recent
+ compress operation.</dd>
+</dl>
 </li>
 </ul>
-<a name="close()">
+<a id="close()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>close</h4>
-<pre>public&nbsp;void&nbsp;close()
-           throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<pre class="methodSignature">public&nbsp;void&nbsp;close()
+           throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Free the native structures associated with this compressor instance.</div>
 <dl>
-<dt><strong>Specified by:</strong></dt>
-<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.io.Closeable</code></dd>
-<dt><strong>Specified by:</strong></dt>
+<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code>close</code>&nbsp;in interface&nbsp;<code>java.lang.AutoCloseable</code></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
+<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.io.Closeable</code></dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="finalize()">
+<a id="finalize()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>finalize</h4>
-<pre>protected&nbsp;void&nbsp;finalize()
+<pre class="methodSignature">protected&nbsp;void&nbsp;finalize()
                  throws java.lang.Throwable</pre>
 <dl>
-<dt><strong>Overrides:</strong></dt>
+<dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code>finalize</code>&nbsp;in class&nbsp;<code>java.lang.Object</code></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Throwable</code></dd></dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code>java.lang.Throwable</code></dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -880,16 +1082,8 @@ public&nbsp;byte[]&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJCompressor.html" target="_top">Frames</a></li>
-<li><a href="TJCompressor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -902,25 +1096,30 @@ public&nbsp;byte[]&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 412dcd4..536f400 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJCustomFilter</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":6};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],4:["t3","Abstract Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJCustomFilter.html" target="_top">Frames</a></li>
-<li><a href="TJCustomFilter.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -57,6 +80,9 @@
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Interface TJCustomFilter" class="title">Interface TJCustomFilter</h2>
 </div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
 <hr>
-<br>
-<pre>public interface <span class="strong">TJCustomFilter</span></pre>
+<pre>public interface <span class="typeNameLabel">TJCustomFilter</span></pre>
 <div class="block">Custom filter callback interface</div>
 </li>
 </ul>
 <ul class="blockList">
 <li class="blockList">
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t3" class="tableTab"><span><a href="javascript:show(4);">Abstract Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html#customFilter(java.nio.ShortBuffer,%20java.awt.Rectangle,%20java.awt.Rectangle,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJTransform)">customFilter</a></strong>(java.nio.ShortBuffer&nbsp;coeffBuffer,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#customFilter(java.nio.ShortBuffer,java.awt.Rectangle,java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJTransform)">customFilter</a></span>&#8203;(java.nio.ShortBuffer&nbsp;coeffBuffer,
             java.awt.Rectangle&nbsp;bufferRegion,
             java.awt.Rectangle&nbsp;planeRegion,
             int&nbsp;componentID,
             int&nbsp;transformID,
-            <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>&nbsp;transform)</code>
+            <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>&nbsp;transform)</code></th>
+<td class="colLast">
 <div class="block">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.</div>
 </table>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 <ul class="blockList">
 <li class="blockList">
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="customFilter(java.nio.ShortBuffer, java.awt.Rectangle, java.awt.Rectangle, int, int, org.libjpegturbo.turbojpeg.TJTransform)">
+<a id="customFilter(java.nio.ShortBuffer,java.awt.Rectangle,java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJTransform)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>customFilter</h4>
-<pre>void&nbsp;customFilter(java.nio.ShortBuffer&nbsp;coeffBuffer,
-                java.awt.Rectangle&nbsp;bufferRegion,
-                java.awt.Rectangle&nbsp;planeRegion,
-                int&nbsp;componentID,
-                int&nbsp;transformID,
-                <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>&nbsp;transform)
-                  throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<pre class="methodSignature">void&nbsp;customFilter&#8203;(java.nio.ShortBuffer&nbsp;coeffBuffer,
+                  java.awt.Rectangle&nbsp;bufferRegion,
+                  java.awt.Rectangle&nbsp;planeRegion,
+                  int&nbsp;componentID,
+                  int&nbsp;transformID,
+                  <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>&nbsp;transform)
+           throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>coeffBuffer</code> - a buffer containing transformed DCT coefficients.
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>coeffBuffer</code> - a buffer containing transformed DCT coefficients.
  (NOTE: this buffer 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.)</dd><dd><code>bufferRegion</code> - rectangle containing the width and height of
+ the callback.)</dd>
+<dd><code>bufferRegion</code> - rectangle containing the width and height of
  <code>coeffBuffer</code> as well as its offset relative to the component
  plane.  TurboJPEG implementations may choose to split each component plane
  into multiple DCT coefficient buffers and call the callback function once
- for each buffer.</dd><dd><code>planeRegion</code> - rectangle containing the width and height of the
- component plane to which <code>coeffBuffer</code> belongs</dd><dd><code>componentID</code> - ID number of the component plane to which
- <code>coeffBuffer</code> belongs (Y, Cb, and Cr have, respectively, ID's
- of 0, 1, and 2 in typical JPEG images.)</dd><dd><code>transformID</code> - ID number of the transformed image to which
+ for each buffer.</dd>
+<dd><code>planeRegion</code> - rectangle containing the width and height of the
+ component plane to which <code>coeffBuffer</code> belongs</dd>
+<dd><code>componentID</code> - ID number of the component plane to which
+ <code>coeffBuffer</code> belongs.  (Y, Cb, and Cr have, respectively, ID's
+ of 0, 1, and 2 in typical JPEG images.)</dd>
+<dd><code>transformID</code> - ID number of the transformed image to which
  <code>coeffBuffer</code> belongs.  This is the same as the index of the
- transform in the <code>transforms</code> array that was passed to <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a>.</dd><dd><code>transform</code> - a <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instance that specifies the
+ transform in the <code>transforms</code> array that was passed to
+ <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a>.</dd>
+<dd><code>transform</code> - a <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instance that specifies the
  parameters and/or cropping region for this transform</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJCustomFilter.html" target="_top">Frames</a></li>
-<li><a href="TJCustomFilter.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
 <li>Constr&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 6666e4e..06de168 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJDecompressor</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10,"i1":42,"i2":42,"i3":42,"i4":42,"i5":42,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10,"i11":10,"i12":10,"i13":10,"i14":10,"i15":10,"i16":10,"i17":42,"i18":42,"i19":10,"i20":42,"i21":10,"i22":10,"i23":42,"i24":10,"i25":10,"i26":10,"i27":42,"i28":42,"i29":42,"i30":10,"i31":10,"i32":10,"i33":10,"i34":10,"i35":10};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJDecompressor.html" target="_top">Frames</a></li>
-<li><a href="TJDecompressor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJDecompressor" class="title">Class TJDecompressor</h2>
 </div>
 <div class="contentContainer">
 <li class="blockList">
 <dl>
 <dt>All Implemented Interfaces:</dt>
-<dd>java.io.Closeable, java.lang.AutoCloseable</dd>
+<dd><code>java.io.Closeable</code>, <code>java.lang.AutoCloseable</code></dd>
 </dl>
 <dl>
 <dt>Direct Known Subclasses:</dt>
-<dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></dd>
+<dd><code><a href="TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></code></dd>
 </dl>
 <hr>
-<br>
-<pre>public class <span class="strong">TJDecompressor</span>
+<pre>public class <span class="typeNameLabel">TJDecompressor</span>
 extends java.lang.Object
 implements java.io.Closeable</pre>
 <div class="block">TurboJPEG decompressor</div>
@@ -114,325 +148,444 @@ implements java.io.Closeable</pre>
 <div class="summary">
 <ul class="blockList">
 <li class="blockList">
-<!-- =========== FIELD SUMMARY =========== -->
-<ul class="blockList">
-<li class="blockList"><a name="field_summary">
-<!--   -->
-</a>
-<h3>Field Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Field Summary table, listing fields, and an explanation">
-<caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
-<tr>
-<th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Field and Description</th>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected long</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#handle">handle</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBuf">jpegBuf</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBufSize">jpegBufSize</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegColorspace">jpegColorspace</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegHeight">jpegHeight</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegSubsamp">jpegSubsamp</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegWidth">jpegWidth</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#yuvImage">yuvImage</a></strong></code>&nbsp;</td>
-</tr>
-</table>
-</li>
-</ul>
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor()">TJDecompressor</a></strong>()</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">TJDecompressor</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG decompresssor instance.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(byte[])">TJDecompressor</a></strong>(byte[]&nbsp;jpegImage)</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D)">TJDecompressor</a></span>&#8203;(byte[]&nbsp;jpegImage)</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image stored in <code>jpegImage</code> with the newly created instance.</div>
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ stored in <code>jpegImage</code> with the newly created instance.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(byte[],%20int)">TJDecompressor</a></strong>(byte[]&nbsp;jpegImage,
-              int&nbsp;imageSize)</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D,int)">TJDecompressor</a></span>&#8203;(byte[]&nbsp;jpegImage,
+              int&nbsp;imageSize)</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image of length <code>imageSize</code> bytes stored in
- <code>jpegImage</code> with the newly created instance.</div>
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
+ with the newly created instance.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor(org.libjpegturbo.turbojpeg.YUVImage)">TJDecompressor</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;yuvImage)</code>
-<div class="block">Create a TurboJPEG decompressor instance and associate the YUV planar
- source image stored in <code>yuvImage</code> with the newly created
- instance.</div>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(org.libjpegturbo.turbojpeg.YUVImage)">TJDecompressor</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;yuvImage)</code></th>
+<td class="colLast">
+<div class="block">Create a TurboJPEG decompressor instance and associate the
+ 8-bit-per-sample planar YUV source image stored in <code>yuvImage</code>
+ with the newly created instance.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t6" class="tableTab"><span><a href="javascript:show(32);">Deprecated Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#close()">close</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#close()">close</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Free the native structures associated with this decompressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(java.awt.image.BufferedImage,%20int)">decompress</a></strong>(java.awt.image.BufferedImage&nbsp;dstImage,
-          int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a decompressed/decoded image to
- the given <code>BufferedImage</code> instance.</div>
-</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int)">decompress</a></strong>(byte[]&nbsp;dstBuf,
-          int&nbsp;desiredWidth,
-          int&nbsp;pitch,
-          int&nbsp;desiredHeight,
-          int&nbsp;pixelFormat,
-          int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a> instead.</i></div>
-</div>
-</td>
-</tr>
-<tr class="rowColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress</a></strong>(byte[]&nbsp;dstBuf,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress(byte%5B%5D,int,int,int,int,int,int,int)">decompress</a></span>&#8203;(byte[]&nbsp;dstBuf,
           int&nbsp;x,
           int&nbsp;y,
           int&nbsp;desiredWidth,
           int&nbsp;pitch,
           int&nbsp;desiredHeight,
           int&nbsp;pixelFormat,
-          int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.</div>
+          int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>,
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="#decompress8(byte%5B%5D,int,int,int,int)"><code>decompress8(byte[], int, int, int, int)</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i2" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress</a></strong>(int[]&nbsp;dstBuf,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress(int%5B%5D,int,int,int,int,int,int,int)">decompress</a></span>&#8203;(int[]&nbsp;dstBuf,
           int&nbsp;x,
           int&nbsp;y,
           int&nbsp;desiredWidth,
           int&nbsp;stride,
           int&nbsp;desiredHeight,
           int&nbsp;pixelFormat,
-          int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.</div>
+          int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(int%5B%5D,int,int,int,int)"><code>decompress8(int[], int, int, int, int)</code></a>
+ instead.</div>
+</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i3" class="rowColor">
 <td class="colFirst"><code>java.awt.image.BufferedImage</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int)">decompress</a></strong>(int&nbsp;desiredWidth,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress(int,int,int,int)">decompress</a></span>&#8203;(int&nbsp;desiredWidth,
           int&nbsp;desiredHeight,
           int&nbsp;bufferedImageType,
-          int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and return a <code>BufferedImage</code>
- instance containing the decompressed/decoded image.</div>
+          int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(int)"><code>decompress8(int)</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i4" class="altColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int,%20int)">decompress</a></strong>(int&nbsp;desiredWidth,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress(int,int,int,int,int)">decompress</a></span>&#8203;(int&nbsp;desiredWidth,
           int&nbsp;pitch,
           int&nbsp;desiredHeight,
           int&nbsp;pixelFormat,
-          int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance and return a buffer containing the decompressed image.</div>
+          int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>,
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="#decompress8(int,int)"><code>decompress8(int, int)</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i5" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(byte[],%20int)">decompressToYUV</a></strong>(byte[]&nbsp;dstBuf,
-               int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>decompressToYUV(YUVImage, int)</code></a> instead.</i></div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress(java.awt.image.BufferedImage,int)">decompress</a></span>&#8203;(java.awt.image.BufferedImage&nbsp;dstImage,
+          int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(java.awt.image.BufferedImage)"><code>decompress8(BufferedImage)</code></a> instead.</div>
 </div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i6" class="altColor">
+<td class="colFirst"><code>short[]</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress12(int,int)">decompress12</a></span>&#8203;(int&nbsp;pitch,
+            int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 12-bit-per-sample
+ packed-pixel decompressed image.</div>
+</td>
+</tr>
+<tr id="i7" class="rowColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress12(short%5B%5D,int,int,int,int)">decompress12</a></span>&#8203;(short[]&nbsp;dstBuf,
+            int&nbsp;x,
+            int&nbsp;y,
+            int&nbsp;pitch,
+            int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and output a 12-bit-per-sample packed-pixel
+ grayscale, RGB, or CMYK image to the given destination buffer.</div>
+</td>
+</tr>
+<tr id="i8" class="altColor">
+<td class="colFirst"><code>short[]</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress16(int,int)">decompress16</a></span>&#8203;(int&nbsp;pitch,
+            int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 16-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 16-bit-per-sample
+ packed-pixel decompressed image.</div>
+</td>
+</tr>
+<tr id="i9" class="rowColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress16(short%5B%5D,int,int,int,int)">decompress16</a></span>&#8203;(short[]&nbsp;dstBuf,
+            int&nbsp;x,
+            int&nbsp;y,
+            int&nbsp;pitch,
+            int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 16-bit-per-sample lossless JPEG source image associated
+ with this decompressor instance and output a 16-bit-per-sample
+ packed-pixel grayscale, RGB, or CMYK image to the given destination
+ buffer.</div>
+</td>
+</tr>
+<tr id="i10" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress8(byte%5B%5D,int,int,int,int)">decompress8</a></span>&#8203;(byte[]&nbsp;dstBuf,
+           int&nbsp;x,
+           int&nbsp;y,
+           int&nbsp;pitch,
+           int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.</div>
+</td>
+</tr>
+<tr id="i11" class="rowColor">
+<td class="colFirst"><code>java.awt.image.BufferedImage</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress8(int)">decompress8</a></span>&#8203;(int&nbsp;bufferedImageType)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ <code>BufferedImage</code> instance containing the 8-bit-per-sample
+ packed-pixel decompressed/decoded image.</div>
+</td>
+</tr>
+<tr id="i12" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress8(int%5B%5D,int,int,int,int)">decompress8</a></span>&#8203;(int[]&nbsp;dstBuf,
+           int&nbsp;x,
+           int&nbsp;y,
+           int&nbsp;stride,
+           int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.</div>
+</td>
+</tr>
+<tr id="i13" class="rowColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)">decompressToYUV</a></strong>(int&nbsp;flags)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)"><code>decompressToYUV(int, int, int, int)</code></a> instead.</i></div>
-</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress8(int,int)">decompress8</a></span>&#8203;(int&nbsp;pitch,
+           int&nbsp;pixelFormat)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ buffer containing an 8-bit-per-sample packed-pixel decompressed image.</div>
 </td>
 </tr>
-<tr class="rowColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int[],%20int,%20int)">decompressToYUV</a></strong>(int&nbsp;desiredWidth,
+<tr id="i14" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompress8(java.awt.image.BufferedImage)">decompress8</a></span>&#8203;(java.awt.image.BufferedImage&nbsp;dstImage)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel decompressed/decoded image to the given
+ <code>BufferedImage</code> instance.</div>
+</td>
+</tr>
+<tr id="i15" class="rowColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(int)">decompressToYUV</a></span>&#8203;(int&nbsp;align)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample unified planar YUV image
+ and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the decompressed image.</div>
+</td>
+</tr>
+<tr id="i16" class="altColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(int%5B%5D)">decompressToYUV</a></span>&#8203;(int[]&nbsp;strides)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into a set of 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the
+ decompressed image planes.</div>
+</td>
+</tr>
+<tr id="i17" class="rowColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(int,int%5B%5D,int,int)">decompressToYUV</a></span>&#8203;(int&nbsp;desiredWidth,
                int[]&nbsp;strides,
                int&nbsp;desiredHeight,
-               int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a set of Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the decompressed image planes.</div>
+               int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(int%5B%5D)"><code>decompressToYUV(int[])</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)">decompressToYUV</a></strong>(int&nbsp;desiredWidth,
-               int&nbsp;pad,
+<tr id="i18" class="altColor">
+<td class="colFirst"><code><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(int,int,int,int)">decompressToYUV</a></span>&#8203;(int&nbsp;desiredWidth,
+               int&nbsp;align,
                int&nbsp;desiredHeight,
-               int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a unified YUV planar image buffer and return a
- <code>YUVImage</code> instance containing the decompressed image.</div>
+               int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(int)"><code>decompressToYUV(int)</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i19" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)">decompressToYUV</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
-               int&nbsp;flags)</code>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a YUV planar image and store it in the given
<code>YUVImage</code> instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)">decompressToYUV</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage)</code></th>
+<td class="colLast">
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample planar YUV image and store
it in the given <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i20" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">decompressToYUV</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
+               int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>decompressToYUV(YUVImage)</code></a> instead.</div>
+</div>
+</td>
+</tr>
+<tr id="i21" class="rowColor">
 <td class="colFirst"><code>protected void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#finalize()">finalize</a></strong>()</code>&nbsp;</td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#finalize()">finalize</a></span>()</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
-<tr class="rowColor">
+<tr id="i22" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getColorspace()">getColorspace</a></strong>()</code>
-<div class="block">Returns the colorspace used in the source image (JPEG or YUV) associated
- with this decompressor instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#get(int)">get</a></span>&#8203;(int&nbsp;param)</code></th>
+<td class="colLast">
+<div class="block">Get the value of a decompression parameter.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i23" class="rowColor">
+<td class="colFirst"><code>int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getColorspace()">getColorspace</a></span>()</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="#get(int)"><code>get</code></a>(<a href="TJ.html#PARAM_COLORSPACE"><code>TJ.PARAM_COLORSPACE</code></a>)</code>
+ instead.</div>
+</div>
+</td>
+</tr>
+<tr id="i24" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getHeight()">getHeight</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getHeight()">getHeight</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the height of the source image (JPEG or YUV) associated with this
  decompressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i25" class="rowColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGBuf()">getJPEGBuf</a></strong>()</code>
-<div class="block">Returns the JPEG image buffer associated with this decompressor instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getJPEGBuf()">getJPEGBuf</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns the JPEG buffer associated with this decompressor instance.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i26" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGSize()">getJPEGSize</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getJPEGSize()">getJPEGSize</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the size of the JPEG image (in bytes) associated with this
  decompressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i27" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,%20int)">getScaledHeight</a></strong>(int&nbsp;desiredWidth,
-               int&nbsp;desiredHeight)</code>
-<div class="block">Returns the height of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getScaledHeight(int,int)">getScaledHeight</a></span>&#8203;(int&nbsp;desiredWidth,
+               int&nbsp;desiredHeight)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i28" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,%20int)">getScaledWidth</a></strong>(int&nbsp;desiredWidth,
-              int&nbsp;desiredHeight)</code>
-<div class="block">Returns the width of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getScaledWidth(int,int)">getScaledWidth</a></span>&#8203;(int&nbsp;desiredWidth,
+              int&nbsp;desiredHeight)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i29" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getSubsamp()">getSubsamp</a></strong>()</code>
-<div class="block">Returns the level of chrominance subsampling used in the source image
- (JPEG or YUV) associated with this decompressor instance.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getSubsamp()">getSubsamp</a></span>()</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="#get(int)"><code>get</code></a>(<a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>)</code>
+ instead.</div>
+</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i30" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getWidth()">getWidth</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getWidth()">getWidth</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the width of the source image (JPEG or YUV) associated with this
  decompressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i31" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setJPEGImage(byte[],%20int)">setJPEGImage</a></strong>(byte[]&nbsp;jpegImage,
-            int&nbsp;imageSize)</code>
-<div class="block"><strong>Deprecated.</strong>&nbsp;
-<div class="block"><i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)"><code>setSourceImage(byte[], int)</code></a> instead.</i></div>
-</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#set(int,int)">set</a></span>&#8203;(int&nbsp;param,
+   int&nbsp;value)</code></th>
+<td class="colLast">
+<div class="block">Set the value of a decompression parameter.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i32" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)">setSourceImage</a></strong>(byte[]&nbsp;jpegImage,
-              int&nbsp;imageSize)</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setCroppingRegion(java.awt.Rectangle)">setCroppingRegion</a></span>&#8203;(java.awt.Rectangle&nbsp;croppingRegion)</code></th>
+<td class="colLast">
+<div class="block">Set the cropping region for partially decompressing a lossy JPEG image
+ into a packed-pixel image.</div>
+</td>
+</tr>
+<tr id="i33" class="rowColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)">setScalingFactor</a></span>&#8203;(<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;scalingFactor)</code></th>
+<td class="colLast">
+<div class="block">Set the scaling factor for subsequent lossy decompression operations.</div>
+</td>
+</tr>
+<tr id="i34" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage(byte%5B%5D,int)">setSourceImage</a></span>&#8203;(byte[]&nbsp;jpegImage,
+              int&nbsp;imageSize)</code></th>
+<td class="colLast">
 <div class="block">Associate the JPEG image or "abbreviated table specification" (AKA
  "tables-only") datastream of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with this decompressor instance.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i35" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</code>
-<div class="block">Associate the specified YUV planar source image with this decompressor
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></span>&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</code></th>
+<td class="colLast">
+<div class="block">Associate the specified planar YUV source image with this decompressor
  instance.</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -440,777 +593,1067 @@ implements java.io.Closeable</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 <div class="details">
 <ul class="blockList">
 <li class="blockList">
-<!-- ============ FIELD DETAIL =========== -->
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="field_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
-<h3>Field Detail</h3>
-<a name="handle">
+<h3>Constructor Detail</h3>
+<a id="&lt;init&gt;()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>handle</h4>
-<pre>protected&nbsp;long handle</pre>
+<h4>TJDecompressor</h4>
+<pre>public&nbsp;TJDecompressor()
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG decompresssor instance.</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="jpegBuf">
+<a id="&lt;init&gt;(byte[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>jpegBuf</h4>
-<pre>protected&nbsp;byte[] jpegBuf</pre>
+<h4>TJDecompressor</h4>
+<pre>public&nbsp;TJDecompressor&#8203;(byte[]&nbsp;jpegImage)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ stored in <code>jpegImage</code> with the newly created instance.  Refer
+ to <a href="#setSourceImage(byte%5B%5D,int)"><code>setSourceImage(byte[], int)</code></a> for more details.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>jpegImage</code> - buffer containing a JPEG source image or tables-only
+ datastream.  (The size of the JPEG image or datastream is assumed to be
+ the length of the array.)  This buffer is not modified.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="jpegBufSize">
+<a id="&lt;init&gt;(byte[],int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>jpegBufSize</h4>
-<pre>protected&nbsp;int jpegBufSize</pre>
+<h4>TJDecompressor</h4>
+<pre>public&nbsp;TJDecompressor&#8203;(byte[]&nbsp;jpegImage,
+                      int&nbsp;imageSize)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
+ image or "abbreviated table specification" (AKA "tables-only") datastream
+ of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
+ with the newly created instance.  Refer to
+ <a href="#setSourceImage(byte%5B%5D,int)"><code>setSourceImage(byte[], int)</code></a> for more details.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>jpegImage</code> - buffer containing a JPEG source image or tables-only
+ datastream.  This buffer is not modified.</dd>
+<dd><code>imageSize</code> - size of the JPEG source image or tables-only datastream
+ (in bytes)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="yuvImage">
+<a id="&lt;init&gt;(org.libjpegturbo.turbojpeg.YUVImage)">
 <!--   -->
 </a>
-<ul class="blockList">
+<ul class="blockListLast">
 <li class="blockList">
-<h4>yuvImage</h4>
-<pre>protected&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a> yuvImage</pre>
+<h4>TJDecompressor</h4>
+<pre>public&nbsp;TJDecompressor&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;yuvImage)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Create a TurboJPEG decompressor instance and associate the
+ 8-bit-per-sample planar YUV source image stored in <code>yuvImage</code>
+ with the newly created instance.  Refer to
+ <a href="#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)"><code>setSourceImage(YUVImage)</code></a> for more details.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>yuvImage</code> - <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing a planar YUV source
+ image to be decoded.  This image is not modified.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
 </li>
 </ul>
-<a name="jpegWidth">
+</section>
+<!-- ============ METHOD DETAIL ========== -->
+<section>
+<ul class="blockList">
+<li class="blockList"><a id="method.detail">
+<!--   -->
+</a>
+<h3>Method Detail</h3>
+<a id="setSourceImage(byte[],int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>jpegWidth</h4>
-<pre>protected&nbsp;int jpegWidth</pre>
+<h4>setSourceImage</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage&#8203;(byte[]&nbsp;jpegImage,
+                           int&nbsp;imageSize)
+                    throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Associate the JPEG image or "abbreviated table specification" (AKA
+ "tables-only") datastream of length <code>imageSize</code> bytes stored in
+ <code>jpegImage</code> with this decompressor instance.  If
+ <code>jpegImage</code> contains a JPEG image, then this image will be used
+ as the source image for subsequent decompression operations.  Passing a
+ tables-only datastream to this method 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.  If a JPEG image is passed to this
+ method, then the <a href="TJ.html#PARAM_STOPONWARNING"><code>parameters</code></a> that describe
+ the JPEG image will be set when the method returns.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>jpegImage</code> - buffer containing a JPEG source image or tables-only
+ datastream.  This buffer is not modified.</dd>
+<dd><code>imageSize</code> - size of the JPEG source image or tables-only datastream
+ (in bytes)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="jpegHeight">
+<a id="setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>jpegHeight</h4>
-<pre>protected&nbsp;int jpegHeight</pre>
+<h4>setSourceImage</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setSourceImage&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</pre>
+<div class="block">Associate the specified planar YUV source image with this decompressor
+ instance.  Subsequent decompression operations will decode this image into
+ a packed-pixel RGB or grayscale destination image.  This method sets
+ <a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a> to the chrominance subsampling level of the
+ source image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>srcImage</code> - <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing a planar YUV source
+ image to be decoded.  This image is not modified.</dd>
+</dl>
 </li>
 </ul>
-<a name="jpegSubsamp">
+<a id="getWidth()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>jpegSubsamp</h4>
-<pre>protected&nbsp;int jpegSubsamp</pre>
+<h4>getWidth</h4>
+<pre class="methodSignature">public&nbsp;int&nbsp;getWidth()</pre>
+<div class="block">Returns the width of the source image (JPEG or YUV) associated with this
+ decompressor instance.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the width of the source image (JPEG or YUV) associated with this
+ decompressor instance.</dd>
+</dl>
 </li>
 </ul>
-<a name="jpegColorspace">
+<a id="getHeight()">
 <!--   -->
 </a>
-<ul class="blockListLast">
+<ul class="blockList">
 <li class="blockList">
-<h4>jpegColorspace</h4>
-<pre>protected&nbsp;int jpegColorspace</pre>
-</li>
-</ul>
+<h4>getHeight</h4>
+<pre class="methodSignature">public&nbsp;int&nbsp;getHeight()</pre>
+<div class="block">Returns the height of the source image (JPEG or YUV) associated with this
+ decompressor instance.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the height of the source image (JPEG or YUV) associated with this
+ decompressor instance.</dd>
+</dl>
 </li>
 </ul>
-<!-- ========= CONSTRUCTOR DETAIL ======== -->
-<ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
-<!--   -->
-</a>
-<h3>Constructor Detail</h3>
-<a name="TJDecompressor()">
+<a id="set(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>TJDecompressor</h4>
-<pre>public&nbsp;TJDecompressor()
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG decompresssor instance.</div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>set</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;set&#8203;(int&nbsp;param,
+                int&nbsp;value)</pre>
+<div class="block">Set the value of a decompression parameter.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>param</code> - one of <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_*</code></a></dd>
+<dd><code>value</code> - value of the decompression parameter (refer to
+ <a href="TJ.html#PARAM_STOPONWARNING"><code>parameter documentation</code></a>)</dd>
+</dl>
 </li>
 </ul>
-<a name="TJDecompressor(byte[])">
+<a id="get(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>TJDecompressor</h4>
-<pre>public&nbsp;TJDecompressor(byte[]&nbsp;jpegImage)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image stored in <code>jpegImage</code> with the newly created instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>jpegImage</code> - JPEG image buffer (size of the JPEG image is assumed to
- be the length of the array.)  This buffer is not modified.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>get</h4>
+<pre class="methodSignature">public&nbsp;int&nbsp;get&#8203;(int&nbsp;param)</pre>
+<div class="block">Get the value of a decompression parameter.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>param</code> - one of <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_*</code></a></dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the value of the specified decompression parameter, or -1 if the
+ value is unknown.</dd>
+</dl>
 </li>
 </ul>
-<a name="TJDecompressor(byte[], int)">
+<a id="setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>TJDecompressor</h4>
-<pre>public&nbsp;TJDecompressor(byte[]&nbsp;jpegImage,
-              int&nbsp;imageSize)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG decompressor instance and associate the JPEG source
- image of length <code>imageSize</code> bytes stored in
- <code>jpegImage</code> with the newly created instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>jpegImage</code> - JPEG image buffer.  This buffer is not modified.</dd><dd><code>imageSize</code> - size of the JPEG image (in bytes)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>setScalingFactor</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setScalingFactor&#8203;(<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;scalingFactor)</pre>
+<div class="block">Set the scaling factor for subsequent lossy decompression operations.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>scalingFactor</code> - <a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJScalingFactor</code></a> instance that specifies a
+ fractional scaling factor that the decompressor supports (see
+ <a href="TJ.html#getScalingFactors()"><code>TJ.getScalingFactors()</code></a>), or <a href="TJ.html#UNSCALED"><code>TJ.UNSCALED</code></a> 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
+ <code>scalingFactor.</code><a href="TJScalingFactor.html#getScaled(int)"><code>getScaled()</code></a>
+ with the JPEG image width and height (see <a href="#getWidth()"><code>getWidth()</code></a> and
+ <a href="#getHeight()"><code>getHeight()</code></a>.)  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 MCU block size
+ (see <a href="TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth()</code></a> and <a href="TJ.html#getMCUHeight(int)"><code>TJ.getMCUHeight()</code></a>.)  Note that decompression scaling is not available
+ (and the specified scaling factor is ignored) when decompressing lossless
+ JPEG images (see <a href="TJ.html#PARAM_LOSSLESS"><code>TJ.PARAM_LOSSLESS</code></a>), since the IDCT algorithm is
+ not used with those images.  Note also that <a href="TJ.html#PARAM_FASTDCT"><code>TJ.PARAM_FASTDCT</code></a> is
+ ignored when decompression scaling is enabled.</dd>
+</dl>
 </li>
 </ul>
-<a name="TJDecompressor(org.libjpegturbo.turbojpeg.YUVImage)">
+<a id="setCroppingRegion(java.awt.Rectangle)">
 <!--   -->
 </a>
-<ul class="blockListLast">
+<ul class="blockList">
 <li class="blockList">
-<h4>TJDecompressor</h4>
-<pre>public&nbsp;TJDecompressor(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;yuvImage)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Create a TurboJPEG decompressor instance and associate the YUV planar
- source image stored in <code>yuvImage</code> with the newly created
- instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>yuvImage</code> - <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing a YUV planar
- image to be decoded.  This image is not modified.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
-</li>
-</ul>
+<h4>setCroppingRegion</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;setCroppingRegion&#8203;(java.awt.Rectangle&nbsp;croppingRegion)
+                       throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Set the cropping region for partially decompressing a lossy JPEG image
+ into a packed-pixel image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>croppingRegion</code> - <code>java.awt.Rectangle</code> instance that
+ specifies a subregion of the JPEG image to decompress, or
+ <a href="TJ.html#UNCROPPED"><code>TJ.UNCROPPED</code></a> for no cropping.  The left boundary of the cropping
+ region must be evenly divisible by the scaled MCU block width, which can
+ be determined by calling <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> with the specified scaling factor (see
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>) and the MCU block width
+ (see <a href="TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth()</code></a>) for the level of chrominance
+ subsampling in the JPEG image (see <a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>.)  The
+ cropping region should be specified relative to the scaled image
+ dimensions.  Unless <code>croppingRegion</code> is <a href="TJ.html#UNCROPPED"><code>TJ.UNCROPPED</code></a>,
+ the JPEG header must be read (see <a href="#setSourceImage(byte%5B%5D,int)"><code>setSourceImage(byte[], int)</code></a>
+ prior to calling this method.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<!-- ============ METHOD DETAIL ========== -->
-<ul class="blockList">
-<li class="blockList"><a name="method_detail">
-<!--   -->
-</a>
-<h3>Method Detail</h3>
-<a name="setSourceImage(byte[], int)">
+<a id="getSubsamp()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setSourceImage</h4>
-<pre>public&nbsp;void&nbsp;setSourceImage(byte[]&nbsp;jpegImage,
-                  int&nbsp;imageSize)
-                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Associate the JPEG image or "abbreviated table specification" (AKA
- "tables-only") datastream of length <code>imageSize</code> bytes stored in
- <code>jpegImage</code> with this decompressor instance.  If
- <code>jpegImage</code> contains a JPEG image, then this image will be used
- as the source image for subsequent decompress operations.  Passing a
- tables-only datastream to this method 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.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>jpegImage</code> - buffer containing a JPEG image or an "abbreviated table
- specification" (AKA "tables-only") datastream.  This buffer is not
- modified.</dd><dd><code>imageSize</code> - size of the JPEG image (in bytes)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>getSubsamp</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;int&nbsp;getSubsamp()</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="#get(int)"><code>get</code></a>(<a href="TJ.html#PARAM_SUBSAMP"><code>TJ.PARAM_SUBSAMP</code></a>)</code>
+ instead.</div>
+</div>
 </li>
 </ul>
-<a name="setJPEGImage(byte[], int)">
+<a id="getColorspace()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setJPEGImage</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;setJPEGImage(byte[]&nbsp;jpegImage,
-                           int&nbsp;imageSize)
-                  throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)"><code>setSourceImage(byte[], int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>getColorspace</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;int&nbsp;getColorspace()</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <code><a href="#get(int)"><code>get</code></a>(<a href="TJ.html#PARAM_COLORSPACE"><code>TJ.PARAM_COLORSPACE</code></a>)</code>
+ instead.</div>
+</div>
 </li>
 </ul>
-<a name="setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">
+<a id="getJPEGBuf()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>setSourceImage</h4>
-<pre>public&nbsp;void&nbsp;setSourceImage(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;srcImage)</pre>
-<div class="block">Associate the specified YUV planar source image with this decompressor
- instance.  Subsequent decompress operations will decode this image into an
- RGB or grayscale destination image.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>srcImage</code> - <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing a YUV planar image to
- be decoded.  This image is not modified.</dd></dl>
+<h4>getJPEGBuf</h4>
+<pre class="methodSignature">public&nbsp;byte[]&nbsp;getJPEGBuf()</pre>
+<div class="block">Returns the JPEG buffer associated with this decompressor instance.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the JPEG buffer associated with this decompressor instance.</dd>
+</dl>
 </li>
 </ul>
-<a name="getWidth()">
+<a id="getJPEGSize()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getWidth</h4>
-<pre>public&nbsp;int&nbsp;getWidth()</pre>
-<div class="block">Returns the width of the source image (JPEG or YUV) associated with this
+<h4>getJPEGSize</h4>
+<pre class="methodSignature">public&nbsp;int&nbsp;getJPEGSize()</pre>
+<div class="block">Returns the size of the JPEG image (in bytes) associated with this
  decompressor instance.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the width of the source image (JPEG or YUV) associated with this
- decompressor instance.</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the size of the JPEG image (in bytes) associated with this
+ decompressor instance.</dd>
+</dl>
 </li>
 </ul>
-<a name="getHeight()">
+<a id="getScaledWidth(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getHeight</h4>
-<pre>public&nbsp;int&nbsp;getHeight()</pre>
-<div class="block">Returns the height of the source image (JPEG or YUV) associated with this
- decompressor instance.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the height of the source image (JPEG or YUV) associated with this
- decompressor instance.</dd></dl>
+<h4>getScaledWidth</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;int&nbsp;getScaledWidth&#8203;(int&nbsp;desiredWidth,
+                          int&nbsp;desiredHeight)</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </li>
 </ul>
-<a name="getSubsamp()">
+<a id="getScaledHeight(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getSubsamp</h4>
-<pre>public&nbsp;int&nbsp;getSubsamp()</pre>
-<div class="block">Returns the level of chrominance subsampling used in the source image
- (JPEG or YUV) associated with this decompressor instance.  See
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the level of chrominance subsampling used in the source image
- (JPEG or YUV) associated with this decompressor instance.</dd></dl>
+<h4>getScaledHeight</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;int&nbsp;getScaledHeight&#8203;(int&nbsp;desiredWidth,
+                           int&nbsp;desiredHeight)</pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a> and
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a> instead.</div>
+</div>
 </li>
 </ul>
-<a name="getColorspace()">
+<a id="decompress8(byte[],int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getColorspace</h4>
-<pre>public&nbsp;int&nbsp;getColorspace()</pre>
-<div class="block">Returns the colorspace used in the source image (JPEG or YUV) associated
- with this decompressor instance.  See <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_RGB"><code>TJ.CS_*</code></a>.  If the
- source image is YUV, then this always returns <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#CS_YCbCr"><code>TJ.CS_YCbCr</code></a>.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the colorspace used in the source image (JPEG or YUV) associated
- with this decompressor instance.</dd></dl>
+<h4>decompress8</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;decompress8&#8203;(byte[]&nbsp;dstBuf,
+                        int&nbsp;x,
+                        int&nbsp;y,
+                        int&nbsp;pitch,
+                        int&nbsp;pixelFormat)
+                 throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.
+ <p>
+ NOTE: The destination image is fully recoverable if this method throws a
+ non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> is
+ set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBuf</code> - buffer that will receive the packed-pixel
+ decompressed/decoded image.  This buffer should normally be
+ <code>pitch * destinationHeight</code> bytes in size.  However, the buffer
+ may also be larger, in which case the <code>x</code>, <code>y</code>, and
+ <code>pitch</code> parameters can be used to specify the region into which
+ the source image should be decompressed/decoded.  NOTE: If the source
+ image is a lossy JPEG image, then <code>destinationHeight</code> is either
+ the scaled JPEG height (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and
+ <a href="#getHeight()"><code>getHeight()</code></a>) or the height of the cropping region (see
+ <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If the source image is a
+ YUV image or a lossless JPEG image, then <code>destinationHeight</code> is
+ the height of the source image.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed/decoded</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed/decoded</dd>
+<dd><code>pitch</code> - bytes per row in the destination image.  Normally this should
+ be set to <code>destinationWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>, if the
+ destination image will be unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>destinationWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  However,
+ you can also use this parameter to specify the row alignment/padding of
+ the destination image, to skip rows, or to decompress/decode into a
+ specific region of a larger image.  NOTE: if the source image is a lossy
+ JPEG image, then <code>destinationWidth</code> is either the scaled JPEG
+ width (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and
+ <a href="#getWidth()"><code>getWidth()</code></a>) or the width of the cropping region (see
+ <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If the source image is a
+ YUV image or a lossless JPEG image, then <code>destinationWidth</code> is
+ the width of the source image.</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed/decoded image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getJPEGBuf()">
+<a id="decompress(byte[],int,int,int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getJPEGBuf</h4>
-<pre>public&nbsp;byte[]&nbsp;getJPEGBuf()</pre>
-<div class="block">Returns the JPEG image buffer associated with this decompressor instance.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the JPEG image buffer associated with this decompressor instance.</dd></dl>
+<h4>decompress</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;decompress&#8203;(byte[]&nbsp;dstBuf,
+                       int&nbsp;x,
+                       int&nbsp;y,
+                       int&nbsp;desiredWidth,
+                       int&nbsp;pitch,
+                       int&nbsp;desiredHeight,
+                       int&nbsp;pixelFormat,
+                       int&nbsp;flags)
+                throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>,
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="#decompress8(byte%5B%5D,int,int,int,int)"><code>decompress8(byte[], int, int, int, int)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getJPEGSize()">
+<a id="decompress8(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getJPEGSize</h4>
-<pre>public&nbsp;int&nbsp;getJPEGSize()</pre>
-<div class="block">Returns the size of the JPEG image (in bytes) associated with this
- decompressor instance.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the size of the JPEG image (in bytes) associated with this
- decompressor instance.</dd></dl>
+<h4>decompress8</h4>
+<pre class="methodSignature">public&nbsp;byte[]&nbsp;decompress8&#8203;(int&nbsp;pitch,
+                          int&nbsp;pixelFormat)
+                   throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ buffer containing an 8-bit-per-sample packed-pixel decompressed image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pitch</code> - see
+ <a href="#decompress8(byte%5B%5D,int,int,int,int)"><code>decompress8(byte[], int, int, int, int)</code></a> for description</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a buffer containing an 8-bit-per-sample packed-pixel decompressed
+ image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getScaledWidth(int, int)">
+<a id="decompress(int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getScaledWidth</h4>
-<pre>public&nbsp;int&nbsp;getScaledWidth(int&nbsp;desiredWidth,
-                 int&nbsp;desiredHeight)</pre>
-<div class="block">Returns the width of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - desired width (in pixels) of the decompressed image.
- Setting this to 0 is the same as setting it to the width of the JPEG image
- (in other words, the width will not be considered when determining the
- scaled image size.)</dd><dd><code>desiredHeight</code> - desired height (in pixels) of the decompressed image.
- Setting this to 0 is the same as setting it to the height of the JPEG
- image (in other words, the height will not be considered when determining
- the scaled image size.)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the width of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</dd></dl>
+<h4>decompress</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;byte[]&nbsp;decompress&#8203;(int&nbsp;desiredWidth,
+                         int&nbsp;pitch,
+                         int&nbsp;desiredHeight,
+                         int&nbsp;pixelFormat,
+                         int&nbsp;flags)
+                  throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>,
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and
+ <a href="#decompress8(int,int)"><code>decompress8(int, int)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getScaledHeight(int, int)">
+<a id="decompress12(short[],int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>getScaledHeight</h4>
-<pre>public&nbsp;int&nbsp;getScaledHeight(int&nbsp;desiredWidth,
-                  int&nbsp;desiredHeight)</pre>
-<div class="block">Returns the height of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - desired width (in pixels) of the decompressed image.
- Setting this to 0 is the same as setting it to the width of the JPEG image
- (in other words, the width will not be considered when determining the
- scaled image size.)</dd><dd><code>desiredHeight</code> - desired height (in pixels) of the decompressed image.
- Setting this to 0 is the same as setting it to the height of the JPEG
- image (in other words, the height will not be considered when determining
- the scaled image size.)</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the height of the largest scaled-down image that the TurboJPEG
- decompressor can generate without exceeding the desired image width and
- height.</dd></dl>
+<h4>decompress12</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;decompress12&#8203;(short[]&nbsp;dstBuf,
+                         int&nbsp;x,
+                         int&nbsp;y,
+                         int&nbsp;pitch,
+                         int&nbsp;pixelFormat)
+                  throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and output a 12-bit-per-sample packed-pixel
+ grayscale, RGB, or CMYK image to the given destination buffer.
+ <p>
+ NOTE: The destination image is fully recoverable if this method throws a
+ non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> is
+ set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBuf</code> - buffer that will receive the packed-pixel
+ decompressed image.  This buffer should normally be
+ <code>pitch * destinationHeight</code> samples in size.  However, the
+ buffer may also be larger, in which case the <code>x</code>,
+ <code>y</code>, and <code>pitch</code> parameters can be used to specify
+ the region into which the source image should be decompressed.  NOTE: If
+ the source image is a lossy JPEG image, then
+ <code>destinationHeight</code> is either the scaled JPEG height (see
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and
+ <a href="#getHeight()"><code>getHeight()</code></a>) or the height of the cropping region (see
+ <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If the source image is a
+ lossless JPEG image, then <code>destinationHeight</code> is the height of
+ the source image.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed</dd>
+<dd><code>pitch</code> - samples per row in the destination image.  Normally this
+ should be set to <code>destinationWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>, if the
+ destination image will be unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>destinationWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  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 image.  NOTE: if the source image is a lossy JPEG
+ image, then <code>destinationWidth</code> is either the scaled JPEG width
+ (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and
+ <a href="#getWidth()"><code>getWidth()</code></a>) or the width of the cropping region (see
+ <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If the source image is a
+ YUV image or a lossless JPEG image, then <code>destinationWidth</code> is
+ the width of the source image.</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(byte[], int, int, int, int, int, int, int)">
+<a id="decompress12(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>decompress</h4>
-<pre>public&nbsp;void&nbsp;decompress(byte[]&nbsp;dstBuf,
-              int&nbsp;x,
-              int&nbsp;y,
-              int&nbsp;desiredWidth,
-              int&nbsp;pitch,
-              int&nbsp;desiredHeight,
-              int&nbsp;pixelFormat,
-              int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.
- <p>
- NOTE: The output image is fully recoverable if this method throws a
- non-fatal <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING"><code>TJ.FLAG_STOPONWARNING</code></a> is specified.)</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstBuf</code> - buffer that will receive the decompressed/decoded image.
- If the source image is a JPEG image, then this buffer should normally be
- <code>pitch * scaledHeight</code> bytes in size, where
- <code>scaledHeight</code> can be determined by calling <code>
- scalingFactor.<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>getScaled</code></a>(jpegHeight)
- </code> with one of the scaling factors returned from <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getScalingFactors()"><code>TJ.getScalingFactors()</code></a> or by calling <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,%20int)"><code>getScaledHeight(int, int)</code></a>.  If the
- source image is a YUV image, then this buffer should normally be
- <code>pitch * height</code> bytes in size, where <code>height</code> is
- the height of the YUV image.  However, the buffer may also be larger than
- the dimensions of the source image, in which case the <code>x</code>,
- <code>y</code>, and <code>pitch</code> parameters can be used to specify
- the region into which the source image should be decompressed/decoded.</dd><dd><code>x</code> - x offset (in pixels) of the region in the destination image into
- which the source image should be decompressed/decoded</dd><dd><code>y</code> - y offset (in pixels) of the region in the destination image into
- which the source image should be decompressed/decoded</dd><dd><code>desiredWidth</code> - If the source image is a JPEG image, then this
- specifies the desired width (in pixels) of the decompressed image (or
- image region.)  If the desired destination image dimensions are different
- than the source image dimensions, then TurboJPEG will use scaling in the
- JPEG decompressor to generate the largest possible image that will fit
- within the desired dimensions.  Setting this to 0 is the same as setting
- it to the width of the JPEG image (in other words, the width will not be
- considered when determining the scaled image size.)  This parameter is
- ignored if the source image is a YUV image.</dd><dd><code>pitch</code> - bytes per line of the destination image.  Normally, this
- should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
- the destination image is unpadded, but you can use this to, for instance,
- pad each line of the destination image to a 4-byte boundary or to
- decompress/decode the source image into a region of a larger image.  NOTE:
- if the source image is a JPEG image, then <code>scaledWidth</code> can be
- determined by calling <code>
- scalingFactor.<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>getScaled</code></a>(jpegWidth)
- </code> or by calling <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,%20int)"><code>getScaledWidth(int, int)</code></a>.  If the source image is a
- YUV image, then <code>scaledWidth</code> is the width of the YUV image.
- Setting this parameter to 0 is the equivalent of setting it to
- <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.</dd><dd><code>desiredHeight</code> - If the source image is a JPEG image, then this
- specifies the desired height (in pixels) of the decompressed image (or
- image region.)  If the desired destination image dimensions are different
- than the source image dimensions, then TurboJPEG will use scaling in the
- JPEG decompressor to generate the largest possible image that will fit
- within the desired dimensions.  Setting this to 0 is the same as setting
- it to the height of the JPEG image (in other words, the height will not be
- considered when determining the scaled image size.)  This parameter is
- ignored if the source image is a YUV image.</dd><dd><code>pixelFormat</code> - pixel format of the decompressed/decoded image (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>decompress12</h4>
+<pre class="methodSignature">public&nbsp;short[]&nbsp;decompress12&#8203;(int&nbsp;pitch,
+                            int&nbsp;pixelFormat)
+                     throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 12-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 12-bit-per-sample
+ packed-pixel decompressed image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pitch</code> - see
+ <a href="#decompress12(short%5B%5D,int,int,int,int)"><code>decompress12(short[], int, int, int, int)</code></a> for description</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a buffer containing an 8-bit-per-sample packed-pixel decompressed
+ image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(byte[], int, int, int, int, int)">
+<a id="decompress16(short[],int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>decompress</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;decompress(byte[]&nbsp;dstBuf,
-                         int&nbsp;desiredWidth,
+<h4>decompress16</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;decompress16&#8203;(short[]&nbsp;dstBuf,
+                         int&nbsp;x,
+                         int&nbsp;y,
                          int&nbsp;pitch,
-                         int&nbsp;desiredHeight,
-                         int&nbsp;pixelFormat,
-                         int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+                         int&nbsp;pixelFormat)
+                  throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 16-bit-per-sample lossless JPEG source image associated
+ with this decompressor instance and output a 16-bit-per-sample
+ packed-pixel grayscale, RGB, or CMYK image to the given destination
+ buffer.
+ <p>
+ NOTE: The destination image is fully recoverable if this method throws a
+ non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> is
+ set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBuf</code> - buffer that will receive the packed-pixel
+ decompressed image.  This buffer should normally be
+ <code>pitch * jpegHeight</code> samples in size.  However, the buffer may
+ also be larger, in which case the <code>x</code>,
+ <code>y</code>, and <code>pitch</code> parameters can be used to specify
+ the region into which the source image should be decompressed.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed</dd>
+<dd><code>pitch</code> - samples per row in the destination image.  Normally this
+ should be set to <code>jpegWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>, if the
+ destination image will be unpadded.  (Setting this parameter to 0 is the
+ equivalent of setting it to <code>jpegWidth *
+ <a href="TJ.html#getPixelSize(int)"><code>TJ.getPixelSize</code></a>(pixelFormat)</code>.)  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 image.</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(int, int, int, int, int)">
+<a id="decompress16(int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>decompress</h4>
-<pre>public&nbsp;byte[]&nbsp;decompress(int&nbsp;desiredWidth,
-                int&nbsp;pitch,
-                int&nbsp;desiredHeight,
-                int&nbsp;pixelFormat,
-                int&nbsp;flags)
-                  throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance and return a buffer containing the decompressed image.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a>
- for description</dd><dd><code>pitch</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a>
- for description</dd><dd><code>desiredHeight</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a>
- for description</dd><dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a buffer containing the decompressed image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<h4>decompress16</h4>
+<pre class="methodSignature">public&nbsp;short[]&nbsp;decompress16&#8203;(int&nbsp;pitch,
+                            int&nbsp;pixelFormat)
+                     throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 16-bit-per-sample JPEG source image associated with this
+ decompressor instance and return a buffer containing a 16-bit-per-sample
+ packed-pixel decompressed image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>pitch</code> - see
+ <a href="#decompress16(short%5B%5D,int,int,int,int)"><code>decompress16(short[], int, int, int, int)</code></a> for description</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a buffer containing an 8-bit-per-sample packed-pixel decompressed
+ image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage, int)">
+<a id="decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompressToYUV</h4>
-<pre>public&nbsp;void&nbsp;decompressToYUV(<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
-                   int&nbsp;flags)
-                     throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a YUV planar image and store it in the given
- <code>YUVImage</code> instance.  This method performs JPEG decompression
- but leaves out the color conversion step, so a planar YUV image is
- generated instead of an RGB or grayscale image.  This method cannot be
+<pre class="methodSignature">public&nbsp;void&nbsp;decompressToYUV&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage)
+                     throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample planar YUV image and store
+ it in the given <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance.  This method performs JPEG
+ decompression but leaves out the color conversion step, so a planar YUV
+ image is generated instead of a packed-pixel image.  This method cannot be
  used to decompress JPEG source images with the CMYK or YCCK colorspace.
  <p>
- NOTE: The YUV planar output image is fully recoverable if this method
- throws a non-fatal <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING"><code>TJ.FLAG_STOPONWARNING</code></a> is specified.)</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstImage</code> - <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance that will receive the YUV planar
- image.  The level of subsampling specified in this <code>YUVImage</code>
- instance must match that of the JPEG image, and the width and height
- specified in the <code>YUVImage</code> instance must match one of the
- scaled image sizes that TurboJPEG is capable of generating from the JPEG
- source image.</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ NOTE: The planar YUV destination image is fully recoverable if this method
+ throws a non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless
+ <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a> is set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstImage</code> - <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance that will receive the planar YUV
+ decompressed image.  The level of subsampling specified in this
+ <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance must match that of the JPEG image, and the width
+ and height specified in the <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance must match the
+ scaled JPEG width and height (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, <a href="#getWidth()"><code>getWidth()</code></a>, and <a href="#getHeight()"><code>getHeight()</code></a>.)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompressToYUV(byte[], int)">
+<a id="decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompressToYUV</h4>
-<pre>@Deprecated
-public&nbsp;void&nbsp;decompressToYUV(byte[]&nbsp;dstBuf,
-                              int&nbsp;flags)
-                     throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)"><code>decompressToYUV(YUVImage, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;decompressToYUV&#8203;(<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;dstImage,
+                            int&nbsp;flags)
+                     throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)"><code>decompressToYUV(YUVImage)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompressToYUV(int, int[], int, int)">
+<a id="decompressToYUV(int[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompressToYUV</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV(int&nbsp;desiredWidth,
-                       int[]&nbsp;strides,
-                       int&nbsp;desiredHeight,
-                       int&nbsp;flags)
-                         throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a set of Y, U (Cb), and V (Cr) image planes and return a
- <code>YUVImage</code> instance containing the decompressed image planes.
- This method performs JPEG decompression but leaves out the color
- conversion step, so a planar YUV image is generated instead of an RGB or
- grayscale image.  This method cannot be used to decompress JPEG source
- images with the CMYK or YCCK colorspace.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - desired width (in pixels) of the YUV image.  If the
- desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
- the width of the JPEG image (in other words, the width will not be
- considered when determining the scaled image size.)</dd><dd><code>strides</code> - an array of integers, each specifying the number of bytes
- per line in the corresponding plane of the output image.  Setting the
- stride for any plane to 0 is the same as setting it to the scaled
- component width of the plane.  If <tt>strides</tt> is NULL, then the
- strides for all planes will be set to their respective scaled component
- widths.  You can adjust the strides in order to add an arbitrary amount of
- line padding to each plane.</dd><dd><code>desiredHeight</code> - desired height (in pixels) of the YUV image.  If the
- desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
- the height of the JPEG image (in other words, the height will not be
- considered when determining the scaled image size.)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a YUV planar image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV&#8203;(int[]&nbsp;strides)
+                         throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into a set of 8-bit-per-sample Y, U (Cb), and V (Cr)
+ image planes and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the
+ decompressed image planes.  This method performs JPEG decompression but
+ leaves out the color conversion step, so a planar YUV image is generated
+ instead of a packed-pixel image.  This method cannot be used to decompress
+ JPEG source images with the CMYK or YCCK colorspace.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>strides</code> - 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 <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a>.)  If <code>strides</code> 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.</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the decompressed image
+ planes</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompressToYUV(int, int, int, int)">
+<a id="decompressToYUV(int,int[],int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompressToYUV</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV(int&nbsp;desiredWidth,
-                       int&nbsp;pad,
-                       int&nbsp;desiredHeight,
-                       int&nbsp;flags)
-                         throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image associated with this decompressor
- instance into a unified YUV planar image buffer and return a
- <code>YUVImage</code> instance containing the decompressed image.  This
- method performs JPEG decompression but leaves out the color conversion
- step, so a planar YUV image is generated instead of an RGB or grayscale
- image.  This method cannot be used to decompress JPEG source images with
- the CMYK or YCCK colorspace.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - desired width (in pixels) of the YUV image.  If the
- desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
- the width of the JPEG image (in other words, the width will not be
- considered when determining the scaled image size.)</dd><dd><code>pad</code> - the width of each line in each plane of the YUV image will be
- padded to the nearest multiple of this number of bytes (must be a power of
- 2.)</dd><dd><code>desiredHeight</code> - desired height (in pixels) of the YUV image.  If the
- desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
- the height of the JPEG image (in other words, the height will not be
- considered when determining the scaled image size.)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a YUV planar image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">@Deprecated
+public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV&#8203;(int&nbsp;desiredWidth,
+                                int[]&nbsp;strides,
+                                int&nbsp;desiredHeight,
+                                int&nbsp;flags)
+                         throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(int%5B%5D)"><code>decompressToYUV(int[])</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompressToYUV(int)">
+<a id="decompressToYUV(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompressToYUV</h4>
-<pre>@Deprecated
-public&nbsp;byte[]&nbsp;decompressToYUV(int&nbsp;flags)
-                       throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block"><span class="strong">Deprecated.</span>&nbsp;<i>Use <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)"><code>decompressToYUV(int, int, int, int)</code></a> instead.</i></div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<pre class="methodSignature">public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV&#8203;(int&nbsp;align)
+                         throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image associated with this
+ decompressor instance into an 8-bit-per-sample unified planar YUV image
+ and return a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the decompressed image.
+ This method performs JPEG decompression but leaves out the color
+ conversion step, so a planar YUV image is generated instead of a
+ packed-pixel image.  This method cannot be used to decompress JPEG source
+ images with the CMYK or YCCK colorspace.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>align</code> - 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.)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>YUVImage</code></a> instance containing the unified planar YUV
+ decompressed image</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(int[], int, int, int, int, int, int, int)">
+<a id="decompressToYUV(int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
-<h4>decompress</h4>
-<pre>public&nbsp;void&nbsp;decompress(int[]&nbsp;dstBuf,
-              int&nbsp;x,
-              int&nbsp;y,
-              int&nbsp;desiredWidth,
-              int&nbsp;stride,
-              int&nbsp;desiredHeight,
-              int&nbsp;pixelFormat,
-              int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a grayscale, RGB, or CMYK image
- to the given destination buffer.
+<h4>decompressToYUV</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a>&nbsp;decompressToYUV&#8203;(int&nbsp;desiredWidth,
+                                int&nbsp;align,
+                                int&nbsp;desiredHeight,
+                                int&nbsp;flags)
+                         throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompressToYUV(int)"><code>decompressToYUV(int)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="decompress8(int[],int,int,int,int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>decompress8</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;decompress8&#8203;(int[]&nbsp;dstBuf,
+                        int&nbsp;x,
+                        int&nbsp;y,
+                        int&nbsp;stride,
+                        int&nbsp;pixelFormat)
+                 throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+ destination buffer.
  <p>
- NOTE: The output image is fully recoverable if this method throws a
- non-fatal <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING"><code>TJ.FLAG_STOPONWARNING</code></a> is specified.)</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstBuf</code> - buffer that will receive the decompressed/decoded image.
- If the source image is a JPEG image, then this buffer should normally be
- <code>stride * scaledHeight</code> pixels in size, where
- <code>scaledHeight</code> can be determined by calling <code>
- scalingFactor.<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>getScaled</code></a>(jpegHeight)
- </code> with one of the scaling factors returned from <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getScalingFactors()"><code>TJ.getScalingFactors()</code></a> or by calling <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,%20int)"><code>getScaledHeight(int, int)</code></a>.  If the
- source image is a YUV image, then this buffer should normally be
- <code>stride * height</code> pixels in size, where <code>height</code> is
- the height of the YUV image.  However, the buffer may also be larger than
- the dimensions of the JPEG image, in which case the <code>x</code>,
- <code>y</code>, and <code>stride</code> parameters can be used to specify
- the region into which the source image should be decompressed.</dd><dd><code>x</code> - x offset (in pixels) of the region in the destination image into
- which the source image should be decompressed/decoded</dd><dd><code>y</code> - y offset (in pixels) of the region in the destination image into
- which the source image should be decompressed/decoded</dd><dd><code>desiredWidth</code> - If the source image is a JPEG image, then this
- specifies the desired width (in pixels) of the decompressed image (or
- image region.)  If the desired destination image dimensions are different
- than the source image dimensions, then TurboJPEG will use scaling in the
- JPEG decompressor to generate the largest possible image that will fit
- within the desired dimensions.  Setting this to 0 is the same as setting
- it to the width of the JPEG image (in other words, the width will not be
- considered when determining the scaled image size.)  This parameter is
- ignored if the source image is a YUV image.</dd><dd><code>stride</code> - pixels per line of the destination image.  Normally, this
- should be set to <code>scaledWidth</code>, but you can use this to, for
- instance, decompress the JPEG image into a region of a larger image.
- NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
- can be determined by calling <code>
- scalingFactor.<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)"><code>getScaled</code></a>(jpegWidth)
- </code> or by calling <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,%20int)"><code>getScaledWidth(int, int)</code></a>.  If the source image is a
- YUV image, then <code>scaledWidth</code> is the width of the YUV image.
- Setting this parameter to 0 is the equivalent of setting it to
- <code>scaledWidth</code>.</dd><dd><code>desiredHeight</code> - If the source image is a JPEG image, then this
- specifies the desired height (in pixels) of the decompressed image (or
- image region.)  If the desired destination image dimensions are different
- than the source image dimensions, then TurboJPEG will use scaling in the
- JPEG decompressor to generate the largest possible image that will fit
- within the desired dimensions.  Setting this to 0 is the same as setting
- it to the height of the JPEG image (in other words, the height will not be
- considered when determining the scaled image size.)  This parameter is
- ignored if the source image is a YUV image.</dd><dd><code>pixelFormat</code> - pixel format of the decompressed image (one of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ NOTE: The destination image is fully recoverable if this method throws a
+ non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a>
+ is set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBuf</code> - buffer that will receive the packed-pixel
+ decompressed/decoded image.  This buffer should normally be
+ <code>stride * destinationHeight</code> pixels in size.  However, the
+ buffer may also be larger, in which case the <code>x</code>,
+ <code>y</code>, and <code>pitch</code> parameters can be used to specify
+ the region into which the source image should be decompressed/decoded.
+ NOTE: If the source image is a lossy JPEG image, then
+ <code>destinationHeight</code> is either the scaled JPEG height (see
+ <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and
+ <a href="#getHeight()"><code>getHeight()</code></a>) or the height of the cropping region (see
+ <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If the source image is a
+ YUV image or a lossless JPEG image, then <code>destinationHeight</code> is
+ the height of the source image.</dd>
+<dd><code>x</code> - x offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed/decoded</dd>
+<dd><code>y</code> - y offset (in pixels) of the region in the destination image into
+ which the source image should be decompressed/decoded</dd>
+<dd><code>stride</code> - pixels per row in the destination image.  Normally this
+ should be set to <code>destinationWidth</code>.  (Setting this parameter
+ to 0 is the equivalent of setting it to <code>destinationWidth</code>.)
+ However, you can also use this parameter to skip rows or to
+ decompress/decode into a specific region of a larger image.  NOTE: if the
+ source image is a lossy JPEG image, then <code>destinationWidth</code> is
+ either the scaled JPEG width (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>, and <a href="#getWidth()"><code>getWidth()</code></a>) or the width of the
+ cropping region (see <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If
+ the source image is a YUV image or a lossless JPEG image, then
+ <code>destinationWidth</code> is the width of the source image.</dd>
+<dd><code>pixelFormat</code> - pixel format of the decompressed/decoded image (one of
+ <a href="TJ.html#PF_RGB"><code>TJ.PF_*</code></a>)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(java.awt.image.BufferedImage, int)">
+<a id="decompress(int[],int,int,int,int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompress</h4>
-<pre>public&nbsp;void&nbsp;decompress(java.awt.image.BufferedImage&nbsp;dstImage,
-              int&nbsp;flags)
-                throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and output a decompressed/decoded image to
- the given <code>BufferedImage</code> instance.
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;decompress&#8203;(int[]&nbsp;dstBuf,
+                       int&nbsp;x,
+                       int&nbsp;y,
+                       int&nbsp;desiredWidth,
+                       int&nbsp;stride,
+                       int&nbsp;desiredHeight,
+                       int&nbsp;pixelFormat,
+                       int&nbsp;flags)
+                throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(int%5B%5D,int,int,int,int)"><code>decompress8(int[], int, int, int, int)</code></a>
+ instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="decompress8(java.awt.image.BufferedImage)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>decompress8</h4>
+<pre class="methodSignature">public&nbsp;void&nbsp;decompress8&#8203;(java.awt.image.BufferedImage&nbsp;dstImage)
+                 throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and output an
+ 8-bit-per-sample packed-pixel decompressed/decoded image to the given
+ <code>BufferedImage</code> instance.
  <p>
- NOTE: The output image is fully recoverable if this method throws a
- non-fatal <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_STOPONWARNING"><code>TJ.FLAG_STOPONWARNING</code></a> is specified.)</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstImage</code> - a <code>BufferedImage</code> instance that will receive
- the decompressed/decoded image.  If the source image is a JPEG image, then
- the width and height of the <code>BufferedImage</code> instance must match
- one of the scaled image sizes that TurboJPEG is capable of generating from
- the JPEG image.  If the source image is a YUV image, then the width and
- height of the <code>BufferedImage</code> instance must match the width and
- height of the YUV image.</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ NOTE: The destination image is fully recoverable if this method throws a
+ non-fatal <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><code>TJException</code></a> (unless <a href="TJ.html#PARAM_STOPONWARNING"><code>TJ.PARAM_STOPONWARNING</code></a>
+ is set.)</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstImage</code> - a <code>BufferedImage</code> instance that will receive
+ the packed-pixel decompressed/decoded image.  If the source image is a
+ lossy JPEG image, then the width and height of the
+ <code>BufferedImage</code> instance must match the scaled JPEG width and
+ height (see <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>,
+ <a href="TJScalingFactor.html#getScaled(int)"><code>TJScalingFactor.getScaled()</code></a>,
+ <a href="#getWidth()"><code>getWidth()</code></a>, and <a href="#getHeight()"><code>getHeight()</code></a>) or the width and height of the
+ cropping region (see <a href="#setCroppingRegion(java.awt.Rectangle)"><code>setCroppingRegion()</code></a>.)  If
+ the source image is a YUV image or a lossless JPEG image, then the width
+ and height of the <code>BufferedImage</code> instance must match the width
+ and height of the source image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="decompress(int, int, int, int)">
+<a id="decompress(java.awt.image.BufferedImage,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>decompress</h4>
-<pre>public&nbsp;java.awt.image.BufferedImage&nbsp;decompress(int&nbsp;desiredWidth,
-                                      int&nbsp;desiredHeight,
-                                      int&nbsp;bufferedImageType,
-                                      int&nbsp;flags)
-                                        throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Decompress the JPEG source image or decode the YUV source image associated
- with this decompressor instance and return a <code>BufferedImage</code>
- instance containing the decompressed/decoded image.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>desiredWidth</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a> for
- description</dd><dd><code>desiredHeight</code> - see
- <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)"><code>decompress(byte[], int, int, int, int, int, int, int)</code></a> for
- description</dd><dd><code>bufferedImageType</code> - the image type of the <code>BufferedImage</code>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;decompress&#8203;(java.awt.image.BufferedImage&nbsp;dstImage,
+                       int&nbsp;flags)
+                throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(java.awt.image.BufferedImage)"><code>decompress8(BufferedImage)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="decompress8(int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>decompress8</h4>
+<pre class="methodSignature">public&nbsp;java.awt.image.BufferedImage&nbsp;decompress8&#8203;(int&nbsp;bufferedImageType)
+                                         throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+ source image associated with this decompressor instance and return a
+ <code>BufferedImage</code> instance containing the 8-bit-per-sample
+ packed-pixel decompressed/decoded image.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>bufferedImageType</code> - the image type of the <code>BufferedImage</code>
  instance that will be created (for instance,
- <code>BufferedImage.TYPE_INT_RGB</code>)</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>a <code>BufferedImage</code> instance containing the
- decompressed/decoded image.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ <code>BufferedImage.TYPE_INT_RGB</code>)</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a <code>BufferedImage</code> instance containing the
+ 8-bit-per-sample packed-pixel decompressed/decoded image.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="close()">
+<a id="decompress(int,int,int,int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>decompress</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;java.awt.image.BufferedImage&nbsp;decompress&#8203;(int&nbsp;desiredWidth,
+                                               int&nbsp;desiredHeight,
+                                               int&nbsp;bufferedImageType,
+                                               int&nbsp;flags)
+                                        throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="#set(int,int)"><code>set()</code></a>, <a href="#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)"><code>setScalingFactor()</code></a>, and <a href="#decompress8(int)"><code>decompress8(int)</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="close()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>close</h4>
-<pre>public&nbsp;void&nbsp;close()
-           throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<pre class="methodSignature">public&nbsp;void&nbsp;close()
+           throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Free the native structures associated with this decompressor instance.</div>
 <dl>
-<dt><strong>Specified by:</strong></dt>
-<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.io.Closeable</code></dd>
-<dt><strong>Specified by:</strong></dt>
+<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
 <dd><code>close</code>&nbsp;in interface&nbsp;<code>java.lang.AutoCloseable</code></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dt><span class="overrideSpecifyLabel">Specified by:</span></dt>
+<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.io.Closeable</code></dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="finalize()">
+<a id="finalize()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>finalize</h4>
-<pre>protected&nbsp;void&nbsp;finalize()
+<pre class="methodSignature">protected&nbsp;void&nbsp;finalize()
                  throws java.lang.Throwable</pre>
 <dl>
-<dt><strong>Overrides:</strong></dt>
+<dt><span class="overrideSpecifyLabel">Overrides:</span></dt>
 <dd><code>finalize</code>&nbsp;in class&nbsp;<code>java.lang.Object</code></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Throwable</code></dd></dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code>java.lang.Throwable</code></dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -1219,16 +1662,8 @@ public&nbsp;byte[]&nbsp;decompressToYUV(int&nbsp;flags)
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJDecompressor.html" target="_top">Frames</a></li>
-<li><a href="TJDecompressor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -1241,25 +1676,30 @@ public&nbsp;byte[]&nbsp;decompressToYUV(int&nbsp;flags)
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 66d73e7..5c2905d 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJException</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJException.html" target="_top">Frames</a></li>
-<li><a href="TJException.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJException" class="title">Class TJException</h2>
 </div>
 <div class="contentContainer">
 <li class="blockList">
 <dl>
 <dt>All Implemented Interfaces:</dt>
-<dd>java.io.Serializable</dd>
+<dd><code>java.io.Serializable</code></dd>
 </dl>
 <hr>
-<br>
-<pre>public class <span class="strong">TJException</span>
+<pre>public class <span class="typeNameLabel">TJException</span>
 extends java.io.IOException</pre>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../serialized-form.html#org.libjpegturbo.turbojpeg.TJException">Serialized Form</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../serialized-form.html#org.libjpegturbo.turbojpeg.TJException">Serialized Form</a></dd>
+</dl>
 </li>
 </ul>
 </div>
@@ -125,65 +162,76 @@ extends java.io.IOException</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#TJException()">TJException</a></strong>()</code>&nbsp;</td>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">TJException</a></span>()</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String)">TJException</a></strong>(java.lang.String&nbsp;message)</code>&nbsp;</td>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.lang.String)">TJException</a></span>&#8203;(java.lang.String&nbsp;message)</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String,%20int)">TJException</a></strong>(java.lang.String&nbsp;message,
-           int&nbsp;code)</code>&nbsp;</td>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.lang.String,int)">TJException</a></span>&#8203;(java.lang.String&nbsp;message,
+           int&nbsp;code)</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.String,%20java.lang.Throwable)">TJException</a></strong>(java.lang.String&nbsp;message,
-           java.lang.Throwable&nbsp;cause)</code>&nbsp;</td>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.lang.String,java.lang.Throwable)">TJException</a></span>&#8203;(java.lang.String&nbsp;message,
+           java.lang.Throwable&nbsp;cause)</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#TJException(java.lang.Throwable)">TJException</a></strong>(java.lang.Throwable&nbsp;cause)</code>&nbsp;</td>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.lang.Throwable)">TJException</a></span>&#8203;(java.lang.Throwable&nbsp;cause)</code></th>
+<td class="colLast">&nbsp;</td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJException.html#getErrorCode()">getErrorCode</a></strong>()</code>
-<div class="block">Returns a code (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getErrorCode()">getErrorCode</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns a code (one of <a href="TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
  last error.</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Throwable">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Throwable">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Throwable</h3>
 <code>addSuppressed, fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, getSuppressed, initCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toString</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -191,6 +239,7 @@ extends java.io.IOException</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -198,12 +247,13 @@ extends java.io.IOException</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="TJException()">
+<a id="&lt;init&gt;()">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -212,80 +262,91 @@ extends java.io.IOException</pre>
 <pre>public&nbsp;TJException()</pre>
 </li>
 </ul>
-<a name="TJException(java.lang.String, java.lang.Throwable)">
+<a id="&lt;init&gt;(java.lang.String,java.lang.Throwable)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJException</h4>
-<pre>public&nbsp;TJException(java.lang.String&nbsp;message,
-           java.lang.Throwable&nbsp;cause)</pre>
+<pre>public&nbsp;TJException&#8203;(java.lang.String&nbsp;message,
+                   java.lang.Throwable&nbsp;cause)</pre>
 </li>
 </ul>
-<a name="TJException(java.lang.String)">
+<a id="&lt;init&gt;(java.lang.String)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJException</h4>
-<pre>public&nbsp;TJException(java.lang.String&nbsp;message)</pre>
+<pre>public&nbsp;TJException&#8203;(java.lang.String&nbsp;message)</pre>
 </li>
 </ul>
-<a name="TJException(java.lang.String, int)">
+<a id="&lt;init&gt;(java.lang.String,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJException</h4>
-<pre>public&nbsp;TJException(java.lang.String&nbsp;message,
-           int&nbsp;code)</pre>
+<pre>public&nbsp;TJException&#8203;(java.lang.String&nbsp;message,
+                   int&nbsp;code)</pre>
 </li>
 </ul>
-<a name="TJException(java.lang.Throwable)">
+<a id="&lt;init&gt;(java.lang.Throwable)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>TJException</h4>
-<pre>public&nbsp;TJException(java.lang.Throwable&nbsp;cause)</pre>
+<pre>public&nbsp;TJException&#8203;(java.lang.Throwable&nbsp;cause)</pre>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="getErrorCode()">
+<a id="getErrorCode()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getErrorCode</h4>
-<pre>public&nbsp;int&nbsp;getErrorCode()</pre>
-<div class="block">Returns a code (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
+<pre class="methodSignature">public&nbsp;int&nbsp;getErrorCode()</pre>
+<div class="block">Returns a code (one of <a href="TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
  last error.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>a code (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
- last error.</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>a code (one of <a href="TJ.html" title="class in org.libjpegturbo.turbojpeg"><code>TJ.ERR_*</code></a>) indicating the severity of the
+ last error.</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -294,16 +355,8 @@ extends java.io.IOException</pre>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJException.html" target="_top">Frames</a></li>
-<li><a href="TJException.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -316,25 +369,30 @@ extends java.io.IOException</pre>
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 4006bac..caa5c58 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJScalingFactor</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJScalingFactor.html" target="_top">Frames</a></li>
-<li><a href="TJScalingFactor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJScalingFactor" class="title">Class TJScalingFactor</h2>
 </div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
 <hr>
-<br>
-<pre>public class <span class="strong">TJScalingFactor</span>
+<pre>public class <span class="typeNameLabel">TJScalingFactor</span>
 extends java.lang.Object</pre>
 <div class="block">Fractional scaling factor</div>
 </li>
@@ -106,72 +140,83 @@ extends java.lang.Object</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#TJScalingFactor(int,%20int)">TJScalingFactor</a></strong>(int&nbsp;num,
-               int&nbsp;denom)</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int)">TJScalingFactor</a></span>&#8203;(int&nbsp;num,
+               int&nbsp;denom)</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG scaling factor instance.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>boolean</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">equals</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;other)</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">equals</a></span>&#8203;(<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;other)</code></th>
+<td class="colLast">
 <div class="block">Returns true or false, depending on whether this instance and
  <code>other</code> have the same numerator and denominator.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getDenom()">getDenom</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getDenom()">getDenom</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns denominator</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i2" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getNum()">getNum</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getNum()">getNum</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns numerator</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i3" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#getScaled(int)">getScaled</a></strong>(int&nbsp;dimension)</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getScaled(int)">getScaled</a></span>&#8203;(int&nbsp;dimension)</code></th>
+<td class="colLast">
 <div class="block">Returns the scaled value of <code>dimension</code>.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i4" class="altColor">
 <td class="colFirst"><code>boolean</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html#isOne()">isOne</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#isOne()">isOne</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns true or false, depending on whether this instance is equal to
  1/1.</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -179,6 +224,7 @@ extends java.lang.Object</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -186,109 +232,139 @@ extends java.lang.Object</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="TJScalingFactor(int, int)">
+<a id="&lt;init&gt;(int,int)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>TJScalingFactor</h4>
-<pre>public&nbsp;TJScalingFactor(int&nbsp;num,
-               int&nbsp;denom)</pre>
+<pre>public&nbsp;TJScalingFactor&#8203;(int&nbsp;num,
+                       int&nbsp;denom)</pre>
 <div class="block">Create a TurboJPEG scaling factor instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>num</code> - numerator</dd><dd><code>denom</code> - denominator</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>num</code> - numerator</dd>
+<dd><code>denom</code> - denominator</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="getNum()">
+<a id="getNum()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getNum</h4>
-<pre>public&nbsp;int&nbsp;getNum()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getNum()</pre>
 <div class="block">Returns numerator</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>numerator</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>numerator</dd>
+</dl>
 </li>
 </ul>
-<a name="getDenom()">
+<a id="getDenom()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getDenom</h4>
-<pre>public&nbsp;int&nbsp;getDenom()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getDenom()</pre>
 <div class="block">Returns denominator</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>denominator</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>denominator</dd>
+</dl>
 </li>
 </ul>
-<a name="getScaled(int)">
+<a id="getScaled(int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getScaled</h4>
-<pre>public&nbsp;int&nbsp;getScaled(int&nbsp;dimension)</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getScaled&#8203;(int&nbsp;dimension)</pre>
 <div class="block">Returns the scaled value of <code>dimension</code>.  This function
  performs the integer equivalent of
  <code>ceil(dimension * scalingFactor)</code>.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dimension</code> - width or height to multiply by this scaling factor</dd>
-<dt><span class="strong">Returns:</span></dt><dd>the scaled value of <code>dimension</code>.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dimension</code> - width or height to multiply by this scaling factor</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the scaled value of <code>dimension</code>.</dd>
+</dl>
 </li>
 </ul>
-<a name="equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">
+<a id="equals(org.libjpegturbo.turbojpeg.TJScalingFactor)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>equals</h4>
-<pre>public&nbsp;boolean&nbsp;equals(<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;other)</pre>
+<pre class="methodSignature">public&nbsp;boolean&nbsp;equals&#8203;(<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a>&nbsp;other)</pre>
 <div class="block">Returns true or false, depending on whether this instance and
  <code>other</code> have the same numerator and denominator.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>other</code> - the scaling factor against which to compare this one</dd>
-<dt><span class="strong">Returns:</span></dt><dd>true or false, depending on whether this instance and
- <code>other</code> have the same numerator and denominator.</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>other</code> - the scaling factor against which to compare this one</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>true or false, depending on whether this instance and
+ <code>other</code> have the same numerator and denominator.</dd>
+</dl>
 </li>
 </ul>
-<a name="isOne()">
+<a id="isOne()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>isOne</h4>
-<pre>public&nbsp;boolean&nbsp;isOne()</pre>
+<pre class="methodSignature">public&nbsp;boolean&nbsp;isOne()</pre>
 <div class="block">Returns true or false, depending on whether this instance is equal to
  1/1.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>true or false, depending on whether this instance is equal to
- 1/1.</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>true or false, depending on whether this instance is equal to
+ 1/1.</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -297,16 +373,8 @@ extends java.lang.Object</pre>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJScalingFactor.html" target="_top">Frames</a></li>
-<li><a href="TJScalingFactor.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -319,25 +387,30 @@ extends java.lang.Object</pre>
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 5f22691..0c2f5cc 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJTransform</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJTransform.html" target="_top">Frames</a></li>
-<li><a href="TJTransform.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
-<li><a href="#nested_classes_inherited_from_class_java.awt.geom.Rectangle2D">Nested</a>&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#methods_inherited_from_class_java.awt.Rectangle">Method</a></li>
+<li><a href="#nested.class.summary">Nested</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
 <li>Method</li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJTransform" class="title">Class TJTransform</h2>
 </div>
 <div class="contentContainer">
 <li class="blockList">
 <dl>
 <dt>All Implemented Interfaces:</dt>
-<dd>java.awt.Shape, java.io.Serializable, java.lang.Cloneable</dd>
+<dd><code>java.awt.Shape</code>, <code>java.io.Serializable</code>, <code>java.lang.Cloneable</code></dd>
 </dl>
 <hr>
-<br>
-<pre>public class <span class="strong">TJTransform</span>
+<pre>public class <span class="typeNameLabel">TJTransform</span>
 extends java.awt.Rectangle</pre>
 <div class="block">Lossless transform parameters</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../serialized-form.html#org.libjpegturbo.turbojpeg.TJTransform">Serialized Form</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../serialized-form.html#org.libjpegturbo.turbojpeg.TJTransform">Serialized Form</a></dd>
+</dl>
 </li>
 </ul>
 </div>
@@ -126,13 +157,14 @@ extends java.awt.Rectangle</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ======== NESTED CLASS SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="nested_class_summary">
+<li class="blockList"><a id="nested.class.summary">
 <!--   -->
 </a>
 <h3>Nested Class Summary</h3>
 <ul class="blockList">
-<li class="blockList"><a name="nested_classes_inherited_from_class_java.awt.geom.Rectangle2D">
+<li class="blockList"><a id="nested.classes.inherited.from.class.java.awt.geom.Rectangle2D">
 <!--   -->
 </a>
 <h3>Nested classes/interfaces inherited from class&nbsp;java.awt.geom.Rectangle2D</h3>
@@ -140,149 +172,188 @@ extends java.awt.Rectangle</pre>
 </ul>
 </li>
 </ul>
+</section>
 <!-- =========== FIELD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="field_summary">
+<li class="blockList"><a id="field.summary">
 <!--   -->
 </a>
 <h3>Field Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Field Summary table, listing fields, and an explanation">
+<table class="memberSummary">
 <caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Field and Description</th>
+<th class="colSecond" scope="col">Field</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#cf">cf</a></strong></code>
+<td class="colFirst"><code><a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#cf">cf</a></span></code></th>
+<td class="colLast">
 <div class="block">Custom filter instance</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#NUMOP">NUMOP</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#NUMOP">NUMOP</a></span></code></th>
+<td class="colLast">
 <div class="block">The number of lossless transform operations</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#op">op</a></strong></code>
-<div class="block">Transform operation (one of <code>OP_*</code>)</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#op">op</a></span></code></th>
+<td class="colLast">
+<div class="block">Transform operation (one of <a href="#OP_NONE"><code>OP_*</code></a>)</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_HFLIP">OP_HFLIP</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_HFLIP">OP_HFLIP</a></span></code></th>
+<td class="colLast">
 <div class="block">Flip (mirror) image horizontally.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE">OP_NONE</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_NONE">OP_NONE</a></span></code></th>
+<td class="colLast">
 <div class="block">Do not transform the position of the image pixels.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT180">OP_ROT180</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_ROT180">OP_ROT180</a></span></code></th>
+<td class="colLast">
 <div class="block">Rotate image 180 degrees.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT270">OP_ROT270</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_ROT270">OP_ROT270</a></span></code></th>
+<td class="colLast">
 <div class="block">Rotate image counter-clockwise by 90 degrees.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_ROT90">OP_ROT90</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_ROT90">OP_ROT90</a></span></code></th>
+<td class="colLast">
 <div class="block">Rotate image clockwise by 90 degrees.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSPOSE">OP_TRANSPOSE</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_TRANSPOSE">OP_TRANSPOSE</a></span></code></th>
+<td class="colLast">
 <div class="block">Transpose image (flip/mirror along upper left to lower right axis).</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_TRANSVERSE">OP_TRANSVERSE</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_TRANSVERSE">OP_TRANSVERSE</a></span></code></th>
+<td class="colLast">
 <div class="block">Transverse transpose image (flip/mirror along upper right to lower left
  axis).</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OP_VFLIP">OP_VFLIP</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OP_VFLIP">OP_VFLIP</a></span></code></th>
+<td class="colLast">
 <div class="block">Flip (mirror) image vertically.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_COPYNONE">OPT_COPYNONE</a></strong></code>
-<div class="block">This option will prevent <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
- and ICC profile data) from the source image to the output image.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_ARITHMETIC">OPT_ARITHMETIC</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will enable arithmetic entropy coding in the JPEG image
+ generated by this particular transform.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_CROP">OPT_CROP</a></strong></code>
-<div class="block">This option will enable lossless cropping.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_COPYNONE">OPT_COPYNONE</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will prevent <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
+ and ICC profile data) from the source image to the destination image.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_GRAY">OPT_GRAY</a></strong></code>
-<div class="block">This option will discard the color data in the input image and produce
- a grayscale output image.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_CROP">OPT_CROP</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will enable lossless cropping.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_NOOUTPUT">OPT_NOOUTPUT</a></strong></code>
-<div class="block">This option will prevent <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from outputting a JPEG image for this
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_GRAY">OPT_GRAY</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will discard the color data in the source image and produce a
+ grayscale destination image.</div>
+</td>
+</tr>
+<tr class="rowColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_NOOUTPUT">OPT_NOOUTPUT</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will prevent <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> from outputting a JPEG image for this
  particular transform.</div>
 </td>
 </tr>
+<tr class="altColor">
+<td class="colFirst"><code>static int</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_OPTIMIZE">OPT_OPTIMIZE</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will enable optimized baseline entropy coding in the JPEG
+ image generated by this particular transform.</div>
+</td>
+</tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT">OPT_PERFECT</a></strong></code>
-<div class="block">This option will cause <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_PERFECT">OPT_PERFECT</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will cause <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
  perfect.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></strong></code>
-<div class="block">This option will enable progressive entropy coding in the output image
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_PROGRESSIVE">OPT_PROGRESSIVE</a></span></code></th>
+<td class="colLast">
+<div class="block">This option will enable progressive entropy coding in the JPEG image
  generated by this particular transform.</div>
 </td>
 </tr>
 <tr class="rowColor">
 <td class="colFirst"><code>static int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_TRIM">OPT_TRIM</a></strong></code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#OPT_TRIM">OPT_TRIM</a></span></code></th>
+<td class="colLast">
 <div class="block">This option will discard any partial MCU blocks that cannot be
  transformed.</div>
 </td>
 </tr>
 <tr class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#options">options</a></strong></code>
-<div class="block">Transform options (bitwise OR of one or more of <code>OPT_*</code>)</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#options">options</a></span></code></th>
+<td class="colLast">
+<div class="block">Transform options (bitwise OR of one or more of
+ <a href="#OPT_PERFECT"><code>OPT_*</code></a>)</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="fields_inherited_from_class_java.awt.Rectangle">
+<li class="blockList"><a id="fields.inherited.from.class.java.awt.Rectangle">
 <!--   -->
 </a>
 <h3>Fields inherited from class&nbsp;java.awt.Rectangle</h3>
 <code>height, width, x, y</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="fields_inherited_from_class_java.awt.geom.Rectangle2D">
+<li class="blockList"><a id="fields.inherited.from.class.java.awt.geom.Rectangle2D">
 <!--   -->
 </a>
 <h3>Fields inherited from class&nbsp;java.awt.geom.Rectangle2D</h3>
@@ -290,80 +361,88 @@ extends java.awt.Rectangle</pre>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform()">TJTransform</a></strong>()</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">TJTransform</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Create a new lossless transform instance.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform(int,%20int,%20int,%20int,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform</a></strong>(int&nbsp;x,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int,int,int,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform</a></span>&#8203;(int&nbsp;x,
            int&nbsp;y,
            int&nbsp;w,
            int&nbsp;h,
            int&nbsp;op,
            int&nbsp;options,
-           <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</code>
+           <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</code></th>
+<td class="colLast">
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform(java.awt.Rectangle,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform</a></strong>(java.awt.Rectangle&nbsp;r,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">TJTransform</a></span>&#8203;(java.awt.Rectangle&nbsp;r,
            int&nbsp;op,
            int&nbsp;options,
-           <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</code>
+           <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</code></th>
+<td class="colLast">
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.awt.Rectangle">
+<li class="blockList"><a id="methods.inherited.from.class.java.awt.Rectangle">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.awt.Rectangle</h3>
 <code>add, add, add, contains, contains, contains, contains, createIntersection, createUnion, equals, getBounds, getBounds2D, getHeight, getLocation, getSize, getWidth, getX, getY, grow, inside, intersection, intersects, isEmpty, move, outcode, reshape, resize, setBounds, setBounds, setLocation, setLocation, setRect, setSize, setSize, toString, translate, union</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.awt.geom.Rectangle2D">
+<li class="blockList"><a id="methods.inherited.from.class.java.awt.geom.Rectangle2D">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.awt.geom.Rectangle2D</h3>
 <code>add, add, add, contains, contains, getPathIterator, getPathIterator, hashCode, intersect, intersects, intersectsLine, intersectsLine, outcode, setFrame, setRect, union</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.awt.geom.RectangularShape">
+<li class="blockList"><a id="methods.inherited.from.class.java.awt.geom.RectangularShape">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.awt.geom.RectangularShape</h3>
 <code>clone, contains, contains, getCenterX, getCenterY, getFrame, getMaxX, getMaxY, getMinX, getMinY, intersects, setFrame, setFrame, setFrameFromCenter, setFrameFromCenter, setFrameFromDiagonal, setFrameFromDiagonal</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
 <code>finalize, getClass, notify, notifyAll, wait, wait, wait</code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.awt.Shape">
+<li class="blockList"><a id="methods.inherited.from.class.java.awt.Shape">
 <!--   -->
 </a>
 <h3>Methods inherited from interface&nbsp;java.awt.Shape</h3>
@@ -371,6 +450,7 @@ extends java.awt.Rectangle</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -378,12 +458,13 @@ extends java.awt.Rectangle</pre>
 <ul class="blockList">
 <li class="blockList">
 <!-- ============ FIELD DETAIL =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="field_detail">
+<li class="blockList"><a id="field.detail">
 <!--   -->
 </a>
 <h3>Field Detail</h3>
-<a name="NUMOP">
+<a id="NUMOP">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -391,10 +472,13 @@ extends java.awt.Rectangle</pre>
 <h4>NUMOP</h4>
 <pre>public static final&nbsp;int NUMOP</pre>
 <div class="block">The number of lossless transform operations</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.NUMOP">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.NUMOP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_NONE">
+<a id="OP_NONE">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -402,10 +486,13 @@ extends java.awt.Rectangle</pre>
 <h4>OP_NONE</h4>
 <pre>public static final&nbsp;int OP_NONE</pre>
 <div class="block">Do not transform the position of the image pixels.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_NONE">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_NONE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_HFLIP">
+<a id="OP_HFLIP">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -414,11 +501,14 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_HFLIP</pre>
 <div class="block">Flip (mirror) image horizontally.  This transform is imperfect if there
  are any partial MCU blocks on the right edge.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_HFLIP">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_HFLIP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_VFLIP">
+<a id="OP_VFLIP">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -427,11 +517,14 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_VFLIP</pre>
 <div class="block">Flip (mirror) image vertically.  This transform is imperfect if there are
  any partial MCU blocks on the bottom edge.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_VFLIP">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_VFLIP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_TRANSPOSE">
+<a id="OP_TRANSPOSE">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -440,11 +533,14 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_TRANSPOSE</pre>
 <div class="block">Transpose image (flip/mirror along upper left to lower right axis).  This
  transform is always perfect.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSPOSE">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSPOSE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_TRANSVERSE">
+<a id="OP_TRANSVERSE">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -454,11 +550,14 @@ extends java.awt.Rectangle</pre>
 <div class="block">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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSVERSE">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_TRANSVERSE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_ROT90">
+<a id="OP_ROT90">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -467,11 +566,14 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_ROT90</pre>
 <div class="block">Rotate image clockwise by 90 degrees.  This transform is imperfect if
  there are any partial MCU blocks on the bottom edge.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT90">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT90">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_ROT180">
+<a id="OP_ROT180">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -480,11 +582,14 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_ROT180</pre>
 <div class="block">Rotate image 180 degrees.  This transform is imperfect if there are any
  partial MCU blocks in the image.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT180">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT180">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OP_ROT270">
+<a id="OP_ROT270">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -493,31 +598,37 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OP_ROT270</pre>
 <div class="block">Rotate image counter-clockwise by 90 degrees.  This transform is imperfect
  if there are any partial MCU blocks on the right edge.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
-<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT270">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="#OPT_PERFECT"><code>OPT_PERFECT</code></a>, 
+<a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OP_ROT270">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_PERFECT">
+<a id="OPT_PERFECT">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>OPT_PERFECT</h4>
 <pre>public static final&nbsp;int OPT_PERFECT</pre>
-<div class="block">This option will cause <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
+<div class="block">This option will cause <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> to throw an exception if the transform is not
  perfect.  Lossless transforms operate on MCU blocks, whose size depends on
  the level of chrominance subsampling used.  If the image's width or height
- is not evenly divisible by the MCU block size (see <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth(int)</code></a>
- and <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUHeight(int)"><code>TJ.getMCUHeight(int)</code></a>), 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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_PERFECT">Constant Field Values</a></dd></dl>
+ is not evenly divisible by the MCU block size (see <a href="TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth()</code></a> and <a href="TJ.html#getMCUHeight(int)"><code>TJ.getMCUHeight()</code></a>), 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.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_PERFECT">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_TRIM">
+<a id="OPT_TRIM">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -526,10 +637,13 @@ extends java.awt.Rectangle</pre>
 <pre>public static final&nbsp;int OPT_TRIM</pre>
 <div class="block">This option will discard any partial MCU blocks that cannot be
  transformed.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_TRIM">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_TRIM">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_CROP">
+<a id="OPT_CROP">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -537,101 +651,154 @@ extends java.awt.Rectangle</pre>
 <h4>OPT_CROP</h4>
 <pre>public static final&nbsp;int OPT_CROP</pre>
 <div class="block">This option will enable lossless cropping.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_CROP">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_CROP">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_GRAY">
+<a id="OPT_GRAY">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>OPT_GRAY</h4>
 <pre>public static final&nbsp;int OPT_GRAY</pre>
-<div class="block">This option will discard the color data in the input image and produce
- a grayscale output image.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_GRAY">Constant Field Values</a></dd></dl>
+<div class="block">This option will discard the color data in the source image and produce a
+ grayscale destination image.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_GRAY">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_NOOUTPUT">
+<a id="OPT_NOOUTPUT">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>OPT_NOOUTPUT</h4>
 <pre>public static final&nbsp;int OPT_NOOUTPUT</pre>
-<div class="block">This option will prevent <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from outputting a JPEG image for this
+<div class="block">This option will prevent <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> 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.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_NOOUTPUT">Constant Field Values</a></dd></dl>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_NOOUTPUT">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_PROGRESSIVE">
+<a id="OPT_PROGRESSIVE">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>OPT_PROGRESSIVE</h4>
 <pre>public static final&nbsp;int OPT_PROGRESSIVE</pre>
-<div class="block">This option will enable progressive entropy coding in the output image
+<div class="block">This option will enable progressive entropy coding in the JPEG image
  generated by this particular transform.  Progressive entropy coding will
  generally improve compression relative to baseline entropy coding (the
- default), but it will reduce compression and decompression performance
- considerably.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_PROGRESSIVE">Constant Field Values</a></dd></dl>
+ default), but it will reduce decompression performance considerably.
+ Can be combined with <a href="#OPT_ARITHMETIC"><code>OPT_ARITHMETIC</code></a>.  Implies
+ <a href="#OPT_OPTIMIZE"><code>OPT_OPTIMIZE</code></a> unless <a href="#OPT_ARITHMETIC"><code>OPT_ARITHMETIC</code></a> is also specified.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_PROGRESSIVE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="OPT_COPYNONE">
+<a id="OPT_COPYNONE">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>OPT_COPYNONE</h4>
 <pre>public static final&nbsp;int OPT_COPYNONE</pre>
-<div class="block">This option will prevent <a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
- and ICC profile data) from the source image to the output image.</div>
-<dl><dt><span class="strong">See Also:</span></dt><dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_COPYNONE">Constant Field Values</a></dd></dl>
+<div class="block">This option will prevent <a href="TJTransformer.html#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>TJTransformer.transform()</code></a> from copying any extra markers (including EXIF
+ and ICC profile data) from the source image to the destination image.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_COPYNONE">Constant Field Values</a></dd>
+</dl>
 </li>
 </ul>
-<a name="op">
+<a id="OPT_ARITHMETIC">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>OPT_ARITHMETIC</h4>
+<pre>public static final&nbsp;int OPT_ARITHMETIC</pre>
+<div class="block">This option will enable arithmetic entropy coding in the JPEG image
+ generated by this particular transform.  Arithmetic entropy coding will
+ generally improve compression relative to Huffman entropy coding (the
+ default), but it will reduce decompression performance considerably.  Can
+ be combined with <a href="#OPT_PROGRESSIVE"><code>OPT_PROGRESSIVE</code></a>.</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_ARITHMETIC">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="OPT_OPTIMIZE">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>OPT_OPTIMIZE</h4>
+<pre>public static final&nbsp;int OPT_OPTIMIZE</pre>
+<div class="block">This option will enable optimized baseline entropy coding in the JPEG
+ image generated by this particular transform.  Optimized baseline entropy
+ coding will improve compression slightly (generally 5% or less.)</div>
+<dl>
+<dt><span class="seeLabel">See Also:</span></dt>
+<dd><a href="../../../constant-values.html#org.libjpegturbo.turbojpeg.TJTransform.OPT_OPTIMIZE">Constant Field Values</a></dd>
+</dl>
+</li>
+</ul>
+<a id="op">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>op</h4>
 <pre>public&nbsp;int op</pre>
-<div class="block">Transform operation (one of <code>OP_*</code>)</div>
+<div class="block">Transform operation (one of <a href="#OP_NONE"><code>OP_*</code></a>)</div>
 </li>
 </ul>
-<a name="options">
+<a id="options">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>options</h4>
 <pre>public&nbsp;int options</pre>
-<div class="block">Transform options (bitwise OR of one or more of <code>OPT_*</code>)</div>
+<div class="block">Transform options (bitwise OR of one or more of
+ <a href="#OPT_PERFECT"><code>OPT_*</code></a>)</div>
 </li>
 </ul>
-<a name="cf">
+<a id="cf">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>cf</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a> cf</pre>
+<pre>public&nbsp;<a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a> cf</pre>
 <div class="block">Custom filter instance</div>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="TJTransform()">
+<a id="&lt;init&gt;()">
 <!--   -->
 </a>
 <ul class="blockList">
@@ -641,62 +808,86 @@ extends java.awt.Rectangle</pre>
 <div class="block">Create a new lossless transform instance.</div>
 </li>
 </ul>
-<a name="TJTransform(int, int, int, int, int, int, org.libjpegturbo.turbojpeg.TJCustomFilter)">
+<a id="&lt;init&gt;(int,int,int,int,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJTransform</h4>
-<pre>public&nbsp;TJTransform(int&nbsp;x,
-           int&nbsp;y,
-           int&nbsp;w,
-           int&nbsp;h,
-           int&nbsp;op,
-           int&nbsp;options,
-           <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</pre>
+<pre>public&nbsp;TJTransform&#8203;(int&nbsp;x,
+                   int&nbsp;y,
+                   int&nbsp;w,
+                   int&nbsp;h,
+                   int&nbsp;op,
+                   int&nbsp;options,
+                   <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</pre>
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>x</code> - the left boundary of the cropping region.  This must be evenly
- divisible by the MCU block width (see <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth(int)</code></a>)</dd><dd><code>y</code> - the upper boundary of the cropping region.  This must be evenly
- divisible by the MCU block height (see <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#getMCUHeight(int)"><code>TJ.getMCUHeight(int)</code></a>)</dd><dd><code>w</code> - the width of the cropping region.  Setting this to 0 is the
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>x</code> - the left boundary of the cropping region.  This must be evenly
+ divisible by the MCU block width (see <a href="TJ.html#getMCUWidth(int)"><code>TJ.getMCUWidth()</code></a>)</dd>
+<dd><code>y</code> - the upper boundary of the cropping region.  This must be evenly
+ divisible by the MCU block height (see <a href="TJ.html#getMCUHeight(int)"><code>TJ.getMCUHeight()</code></a>)</dd>
+<dd><code>w</code> - the width of the cropping region.  Setting this to 0 is the
  equivalent of setting it to (width of the source JPEG image -
- <code>x</code>).</dd><dd><code>h</code> - the height of the cropping region.  Setting this to 0 is the
+ <code>x</code>).</dd>
+<dd><code>h</code> - the height of the cropping region.  Setting this to 0 is the
  equivalent of setting it to (height of the source JPEG image -
- <code>y</code>).</dd><dd><code>op</code> - one of the transform operations (<code>OP_*</code>)</dd><dd><code>options</code> - the bitwise OR of one or more of the transform options
- (<code>OPT_*</code>)</dd><dd><code>cf</code> - an instance of an object that implements the <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><code>TJCustomFilter</code></a> interface, or null if no custom filter is needed</dd></dl>
+ <code>y</code>).</dd>
+<dd><code>op</code> - one of the transform operations (<a href="#OP_NONE"><code>OP_*</code></a>)</dd>
+<dd><code>options</code> - the bitwise OR of one or more of the transform options
+ (<a href="#OPT_PERFECT"><code>OPT_*</code></a>)</dd>
+<dd><code>cf</code> - an instance of an object that implements the
+ <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><code>TJCustomFilter</code></a> interface, or null if no custom filter is needed</dd>
+</dl>
 </li>
 </ul>
-<a name="TJTransform(java.awt.Rectangle, int, int, org.libjpegturbo.turbojpeg.TJCustomFilter)">
+<a id="&lt;init&gt;(java.awt.Rectangle,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>TJTransform</h4>
-<pre>public&nbsp;TJTransform(java.awt.Rectangle&nbsp;r,
-           int&nbsp;op,
-           int&nbsp;options,
-           <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</pre>
+<pre>public&nbsp;TJTransform&#8203;(java.awt.Rectangle&nbsp;r,
+                   int&nbsp;op,
+                   int&nbsp;options,
+                   <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a>&nbsp;cf)</pre>
 <div class="block">Create a new lossless transform instance with the given parameters.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>r</code> - a <code>Rectangle</code> instance that specifies the cropping
- region.  See <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html#TJTransform(int,%20int,%20int,%20int,%20int,%20int,%20org.libjpegturbo.turbojpeg.TJCustomFilter)"><code>TJTransform(int, int, int, int, int, int, TJCustomFilter)</code></a> for more
- detail.</dd><dd><code>op</code> - one of the transform operations (<code>OP_*</code>)</dd><dd><code>options</code> - the bitwise OR of one or more of the transform options
- (<code>OPT_*</code>)</dd><dd><code>cf</code> - an instance of an object that implements the <a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><code>TJCustomFilter</code></a> interface, or null if no custom filter is needed</dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>r</code> - a <code>java.awt.Rectangle</code> instance that specifies the
+ cropping region.  See
+ <a href="#%3Cinit%3E(int,int,int,int,int,int,org.libjpegturbo.turbojpeg.TJCustomFilter)"><code>TJTransform(int, int, int, int, int, int, TJCustomFilter)</code></a> for
+ more details.</dd>
+<dd><code>op</code> - one of the transform operations (<a href="#OP_NONE"><code>OP_*</code></a>)</dd>
+<dd><code>options</code> - the bitwise OR of one or more of the transform options
+ (<a href="#OPT_PERFECT"><code>OPT_*</code></a>)</dd>
+<dd><code>cf</code> - an instance of an object that implements the
+ <a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><code>TJCustomFilter</code></a> interface, or null if no custom filter is needed</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -705,16 +896,8 @@ extends java.awt.Rectangle</pre>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJTransform.html" target="_top">Frames</a></li>
-<li><a href="TJTransform.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -727,25 +910,30 @@ extends java.awt.Rectangle</pre>
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
-<li><a href="#nested_classes_inherited_from_class_java.awt.geom.Rectangle2D">Nested</a>&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#methods_inherited_from_class_java.awt.Rectangle">Method</a></li>
+<li><a href="#nested.class.summary">Nested</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.summary">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#field.detail">Field</a>&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
 <li>Method</li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index a30fe30..83836ea 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>TJTransformer</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10,"i1":10,"i2":42,"i3":10,"i4":42};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"],32:["t6","Deprecated Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJTransformer.html" target="_top">Frames</a></li>
-<li><a href="TJTransformer.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#fields_inherited_from_class_org.libjpegturbo.turbojpeg.TJDecompressor">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class TJTransformer" class="title">Class TJTransformer</h2>
 </div>
 <div class="contentContainer">
 <li>java.lang.Object</li>
 <li>
 <ul class="inheritance">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">org.libjpegturbo.turbojpeg.TJDecompressor</a></li>
+<li><a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">org.libjpegturbo.turbojpeg.TJDecompressor</a></li>
 <li>
 <ul class="inheritance">
 <li>org.libjpegturbo.turbojpeg.TJTransformer</li>
 <li class="blockList">
 <dl>
 <dt>All Implemented Interfaces:</dt>
-<dd>java.io.Closeable, java.lang.AutoCloseable</dd>
+<dd><code>java.io.Closeable</code>, <code>java.lang.AutoCloseable</code></dd>
 </dl>
 <hr>
-<br>
-<pre>public class <span class="strong">TJTransformer</span>
-extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></pre>
+<pre>public class <span class="typeNameLabel">TJTransformer</span>
+extends <a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></pre>
 <div class="block">TurboJPEG lossless transformer</div>
 </li>
 </ul>
@@ -114,102 +148,120 @@ extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title=
 <div class="summary">
 <ul class="blockList">
 <li class="blockList">
-<!-- =========== FIELD SUMMARY =========== -->
-<ul class="blockList">
-<li class="blockList"><a name="field_summary">
-<!--   -->
-</a>
-<h3>Field Summary</h3>
-<ul class="blockList">
-<li class="blockList"><a name="fields_inherited_from_class_org.libjpegturbo.turbojpeg.TJDecompressor">
-<!--   -->
-</a>
-<h3>Fields inherited from class&nbsp;org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></h3>
-<code><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#handle">handle</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBuf">jpegBuf</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegBufSize">jpegBufSize</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegColorspace">jpegColorspace</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegHeight">jpegHeight</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegSubsamp">jpegSubsamp</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#jpegWidth">jpegWidth</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#yuvImage">yuvImage</a></code></li>
-</ul>
-</li>
-</ul>
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer()">TJTransformer</a></strong>()</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E()">TJTransformer</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG lossless transformer instance.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer(byte[])">TJTransformer</a></strong>(byte[]&nbsp;jpegImage)</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D)">TJTransformer</a></span>&#8203;(byte[]&nbsp;jpegImage)</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image stored in <code>jpegImage</code> with the newly created instance.</div>
+ source image stored in <code>jpegImage</code> with the newly created
+ instance.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#TJTransformer(byte[],%20int)">TJTransformer</a></strong>(byte[]&nbsp;jpegImage,
-             int&nbsp;imageSize)</code>
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D,int)">TJTransformer</a></span>&#8203;(byte[]&nbsp;jpegImage,
+             int&nbsp;imageSize)</code></th>
+<td class="colLast">
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image of length <code>imageSize</code> bytes stored in
source image of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with the newly created instance.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t6" class="tableTab"><span><a href="javascript:show(32);">Deprecated Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>int[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#getTransformedSizes()">getTransformedSizes</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getTransformedSizes()">getTransformedSizes</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns an array containing the sizes of the transformed JPEG images
- generated by the most recent transform operation.</div>
(in bytes) generated by the most recent transform operation.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(byte[][],%20org.libjpegturbo.turbojpeg.TJTransform[],%20int)">transform</a></strong>(byte[][]&nbsp;dstBufs,
-         <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
-         int&nbsp;flags)</code>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
instance into one or more JPEG images stored in the given destination
- buffers.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)">transform</a></span>&#8203;(byte[][]&nbsp;dstBufs,
+         <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms)</code></th>
+<td class="colLast">
+<div class="block">Losslessly transform the JPEG source image associated with this
transformer instance into one or more JPEG images stored in the given
destination buffers.</div>
 </td>
 </tr>
-<tr class="altColor">
-<td class="colFirst"><code><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html#transform(org.libjpegturbo.turbojpeg.TJTransform[],%20int)">transform</a></strong>(<a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
-         int&nbsp;flags)</code>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
- instance and return an array of <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a> instances, each of
- which has a transformed JPEG image associated with it.</div>
+<tr id="i2" class="altColor">
+<td class="colFirst"><code>void</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D,int)">transform</a></span>&#8203;(byte[][]&nbsp;dstBufs,
+         <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
+         int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>transform(byte[][], TJTransform[])</code></a> instead.</div>
+</div>
+</td>
+</tr>
+<tr id="i3" class="rowColor">
+<td class="colFirst"><code><a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D)">transform</a></span>&#8203;(<a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms)</code></th>
+<td class="colLast">
+<div class="block">Losslessly transform the JPEG source image associated with this
+ transformer instance and return an array of <a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a>
+ instances, each of which has a transformed JPEG image associated with it.</div>
+</td>
+</tr>
+<tr id="i4" class="altColor">
+<td class="colFirst"><code><a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]</code></td>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D,int)">transform</a></span>&#8203;(<a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
+         int&nbsp;flags)</code></th>
+<td class="colLast">
+<div class="block"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>transform(TJTransform[])</code></a> instead.</div>
+</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_org.libjpegturbo.turbojpeg.TJDecompressor">
+<li class="blockList"><a id="methods.inherited.from.class.org.libjpegturbo.turbojpeg.TJDecompressor">
 <!--   -->
 </a>
-<h3>Methods inherited from class&nbsp;org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></h3>
-<code><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#close()">close</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(java.awt.image.BufferedImage,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(byte[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int[],%20int,%20int,%20int,%20int,%20int,%20int,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompress(int,%20int,%20int,%20int,%20int)">decompress</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(byte[],%20int)">decompressToYUV</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int)">decompressToYUV</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int[],%20int,%20int)">decompressToYUV</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(int,%20int,%20int,%20int)">decompressToYUV</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,%20int)">decompressToYUV</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#finalize()">finalize</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getColorspace()">getColorspace</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getHeight()">getHeight</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGBuf()">getJPEGBuf</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getJPEGSize()">getJPEGSize</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledHeight(int,%20int)">getScaledHeight</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getScaledWidth(int,%20int)">getScaledWidth</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getSubsamp()">getSubsamp</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#getWidth()">getWidth</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setJPEGImage(byte[],%20int)">setJPEGImage</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(byte[],%20int)">setSourceImage</a>, <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></code></li>
+<h3>Methods inherited from class&nbsp;org.libjpegturbo.turbojpeg.<a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></h3>
+<code><a href="TJDecompressor.html#close()">close</a>, <a href="TJDecompressor.html#decompress(byte%5B%5D,int,int,int,int,int,int,int)">decompress</a>, <a href="TJDecompressor.html#decompress(int%5B%5D,int,int,int,int,int,int,int)">decompress</a>, <a href="TJDecompressor.html#decompress(int,int,int,int)">decompress</a>, <a href="TJDecompressor.html#decompress(int,int,int,int,int)">decompress</a>, <a href="TJDecompressor.html#decompress(java.awt.image.BufferedImage,int)">decompress</a>, <a href="TJDecompressor.html#decompress12(int,int)">decompress12</a>, <a href="TJDecompressor.html#decompress12(short%5B%5D,int,int,int,int)">decompress12</a>, <a href="TJDecompressor.html#decompress16(int,int)">decompress16</a>, <a href="TJDecompressor.html#decompress16(short%5B%5D,int,int,int,int)">decompress16</a>, <a href="TJDecompressor.html#decompress8(byte%5B%5D,int,int,int,int)">decompress8</a>, <a href="TJDecompressor.html#decompress8(int)">decompress8</a>, <a href="TJDecompressor.html#decompress8(int%5B%5D,int,int,int,int)">decompress8</a>, <a href="TJDecompressor.html#decompress8(int,int)">decompress8</a>, <a href="TJDecompressor.html#decompress8(java.awt.image.BufferedImage)">decompress8</a>, <a href="TJDecompressor.html#decompressToYUV(int)">decompressToYUV</a>, <a href="TJDecompressor.html#decompressToYUV(int%5B%5D)">decompressToYUV</a>, <a href="TJDecompressor.html#decompressToYUV(int,int%5B%5D,int,int)">decompressToYUV</a>, <a href="TJDecompressor.html#decompressToYUV(int,int,int,int)">decompressToYUV</a>, <a href="TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage)">decompressToYUV</a>, <a href="TJDecompressor.html#decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage,int)">decompressToYUV</a>, <a href="TJDecompressor.html#finalize()">finalize</a>, <a href="TJDecompressor.html#get(int)">get</a>, <a href="TJDecompressor.html#getColorspace()">getColorspace</a>, <a href="TJDecompressor.html#getHeight()">getHeight</a>, <a href="TJDecompressor.html#getJPEGBuf()">getJPEGBuf</a>, <a href="TJDecompressor.html#getJPEGSize()">getJPEGSize</a>, <a href="TJDecompressor.html#getScaledHeight(int,int)">getScaledHeight</a>, <a href="TJDecompressor.html#getScaledWidth(int,int)">getScaledWidth</a>, <a href="TJDecompressor.html#getSubsamp()">getSubsamp</a>, <a href="TJDecompressor.html#getWidth()">getWidth</a>, <a href="TJDecompressor.html#set(int,int)">set</a>, <a href="TJDecompressor.html#setCroppingRegion(java.awt.Rectangle)">setCroppingRegion</a>, <a href="TJDecompressor.html#setScalingFactor(org.libjpegturbo.turbojpeg.TJScalingFactor)">setScalingFactor</a>, <a href="TJDecompressor.html#setSourceImage(byte%5B%5D,int)">setSourceImage</a>, <a href="TJDecompressor.html#setSourceImage(org.libjpegturbo.turbojpeg.YUVImage)">setSourceImage</a></code></li>
 </ul>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -217,6 +269,7 @@ extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title=
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
@@ -224,149 +277,219 @@ extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title=
 <ul class="blockList">
 <li class="blockList">
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="TJTransformer()">
+<a id="&lt;init&gt;()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJTransformer</h4>
 <pre>public&nbsp;TJTransformer()
-              throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+              throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Create a TurboJPEG lossless transformer instance.</div>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="TJTransformer(byte[])">
+<a id="&lt;init&gt;(byte[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>TJTransformer</h4>
-<pre>public&nbsp;TJTransformer(byte[]&nbsp;jpegImage)
-              throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<pre>public&nbsp;TJTransformer&#8203;(byte[]&nbsp;jpegImage)
+              throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image stored in <code>jpegImage</code> with the newly created instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>jpegImage</code> - JPEG image buffer (size of the JPEG image is assumed to
- be the length of the array.)  This buffer is not modified.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ source image stored in <code>jpegImage</code> with the newly created
+ instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>jpegImage</code> - buffer containing the JPEG source image to transform.
+ (The size of the JPEG image is assumed to be the length of the array.)
+ This buffer is not modified.</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="TJTransformer(byte[], int)">
+<a id="&lt;init&gt;(byte[],int)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>TJTransformer</h4>
-<pre>public&nbsp;TJTransformer(byte[]&nbsp;jpegImage,
-             int&nbsp;imageSize)
-              throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<pre>public&nbsp;TJTransformer&#8203;(byte[]&nbsp;jpegImage,
+                     int&nbsp;imageSize)
+              throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Create a TurboJPEG lossless transformer instance and associate the JPEG
- image of length <code>imageSize</code> bytes stored in
source image of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with the newly created instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>jpegImage</code> - JPEG image buffer.  This buffer is not modified.</dd><dd><code>imageSize</code> - size of the JPEG image (in bytes)</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>jpegImage</code> - buffer containing the JPEG source image to transform.
+ This buffer is not modified.</dd>
+<dd><code>imageSize</code> - size of the JPEG source image (in bytes)</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="transform(byte[][], org.libjpegturbo.turbojpeg.TJTransform[], int)">
+<a id="transform(byte[][],org.libjpegturbo.turbojpeg.TJTransform[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>transform</h4>
-<pre>public&nbsp;void&nbsp;transform(byte[][]&nbsp;dstBufs,
-             <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
-             int&nbsp;flags)
-               throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
- instance into one or more JPEG images stored in the given destination
- buffers.  Lossless transforms work by moving the raw 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 method provides a means of
- generating multiple transformed images from the same source or of applying
- multiple transformations simultaneously, in order to eliminate the need to
- read the source coefficients multiple times.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>dstBufs</code> - an array of image buffers.  <code>dstbufs[i]</code> will
- receive a JPEG image that has been transformed using the parameters in
- <code>transforms[i]</code>.  Use <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSize(int,%20int,%20int)"><code>TJ.bufSize(int, int, int)</code></a> to determine the
- maximum size for each buffer based on the transformed or cropped width and
- height and the level of subsampling used in the source image.</dd><dd><code>transforms</code> - an array of <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instances, each of
+<pre class="methodSignature">public&nbsp;void&nbsp;transform&#8203;(byte[][]&nbsp;dstBufs,
+                      <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Losslessly transform the JPEG source image associated with this
+ transformer instance into one or more JPEG images stored in the given
+ destination buffers.  Lossless transforms work by moving the raw
+ 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 method
+ provides a means of generating multiple transformed images from the same
+ source or of applying multiple transformations simultaneously, in order to
+ eliminate the need to read the source coefficients multiple times.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>dstBufs</code> - an array of JPEG destination buffers.
+ <code>dstbufs[i]</code> will receive a JPEG image that has been
+ transformed using the parameters in <code>transforms[i]</code>.  Use
+ <a href="TJ.html#bufSize(int,int,int)"><code>TJ.bufSize()</code></a> to determine the maximum size for each
+ buffer based on the transformed or cropped width and height and the level
+ of subsampling used in the source image.</dd>
+<dd><code>transforms</code> - an array of <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instances, each of
  which specifies the transform parameters and/or cropping region for the
- corresponding transformed output image</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+ corresponding transformed JPEG image</dd>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="transform(byte[][],org.libjpegturbo.turbojpeg.TJTransform[],int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>transform</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;void&nbsp;transform&#8203;(byte[][]&nbsp;dstBufs,
+                      <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
+                      int&nbsp;flags)
+               throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="#transform(byte%5B%5D%5B%5D,org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>transform(byte[][], TJTransform[])</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="transform(org.libjpegturbo.turbojpeg.TJTransform[], int)">
+<a id="transform(org.libjpegturbo.turbojpeg.TJTransform[])">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>transform</h4>
-<pre>public&nbsp;<a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]&nbsp;transform(<a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
-                         int&nbsp;flags)
-                           throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
-<div class="block">Losslessly transform the JPEG image associated with this transformer
- instance and return an array of <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a> instances, each of
- which has a transformed JPEG image associated with it.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>transforms</code> - an array of <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instances, each of
+<pre class="methodSignature">public&nbsp;<a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]&nbsp;transform&#8203;(<a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms)
+                           throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="block">Losslessly transform the JPEG source image associated with this
+ transformer instance and return an array of <a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a>
+ instances, each of which has a transformed JPEG image associated with it.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>transforms</code> - an array of <a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><code>TJTransform</code></a> instances, each of
  which specifies the transform parameters and/or cropping region for the
- corresponding transformed output image</dd><dd><code>flags</code> - the bitwise OR of one or more of
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#FLAG_BOTTOMUP"><code>TJ.FLAG_*</code></a></dd>
-<dt><span class="strong">Returns:</span></dt><dd>an array of <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a> instances, each of
+ corresponding transformed JPEG image</dd>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>an array of <a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><code>TJDecompressor</code></a> instances, each of
  which has a transformed JPEG image associated with it.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
+</li>
+</ul>
+<a id="transform(org.libjpegturbo.turbojpeg.TJTransform[],int)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>transform</h4>
+<pre class="methodSignature">@Deprecated
+public&nbsp;<a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a>[]&nbsp;transform&#8203;(<a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>[]&nbsp;transforms,
+                                  int&nbsp;flags)
+                           throws <a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
+<div class="deprecationBlock"><span class="deprecatedLabel">Deprecated.</span>
+<div class="deprecationComment">Use <a href="TJDecompressor.html#set(int,int)"><code>TJDecompressor.set()</code></a> and
+ <a href="#transform(org.libjpegturbo.turbojpeg.TJTransform%5B%5D)"><code>transform(TJTransform[])</code></a> instead.</div>
+</div>
+<dl>
+<dt><span class="throwsLabel">Throws:</span></dt>
+<dd><code><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd>
+</dl>
 </li>
 </ul>
-<a name="getTransformedSizes()">
+<a id="getTransformedSizes()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getTransformedSizes</h4>
-<pre>public&nbsp;int[]&nbsp;getTransformedSizes()</pre>
+<pre class="methodSignature">public&nbsp;int[]&nbsp;getTransformedSizes()</pre>
 <div class="block">Returns an array containing the sizes of the transformed JPEG images
- generated by the most recent transform operation.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>an array containing the sizes of the transformed JPEG images
- generated by the most recent transform operation.</dd></dl>
+ (in bytes) generated by the most recent transform operation.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>an array containing the sizes of the transformed JPEG images
+ (in bytes) generated by the most recent transform operation.</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -375,16 +498,8 @@ extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title=
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next Class</span></a></li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/TJTransformer.html" target="_top">Frames</a></li>
-<li><a href="TJTransformer.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -397,25 +512,30 @@ extends <a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title=
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#fields_inherited_from_class_org.libjpegturbo.turbojpeg.TJDecompressor">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
 <li>Field&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index d4485ed..2654c21 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>YUVImage</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var data = {"i0":10,"i1":10,"i2":10,"i3":10,"i4":10,"i5":10,"i6":10,"i7":10,"i8":10,"i9":10,"i10":10};
+var tabs = {65535:["t0","All Methods"],2:["t2","Instance Methods"],8:["t4","Concrete Methods"]};
+var altColor = "altColor";
+var rowColor = "rowColor";
+var tableTab = "tableTab";
+var activeTableTab = "activeTableTab";
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li>Next Class</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/YUVImage.html" target="_top">Frames</a></li>
-<li><a href="YUVImage.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
 <!-- ======== START OF CLASS DATA ======== -->
+<main role="main">
 <div class="header">
-<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<div class="subTitle"><span class="packageLabelInType">Package</span>&nbsp;<a href="package-summary.html">org.libjpegturbo.turbojpeg</a></div>
 <h2 title="Class YUVImage" class="title">Class YUVImage</h2>
 </div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
 <hr>
-<br>
-<pre>public class <span class="strong">YUVImage</span>
+<pre>public class <span class="typeNameLabel">YUVImage</span>
 extends java.lang.Object</pre>
-<div class="block">This class encapsulates a YUV planar image and the metadata
+<div class="block">This class encapsulates a planar YUV image and the metadata
  associated with it.  The TurboJPEG API allows both the JPEG compression and
  decompression pipelines to be split into stages:  YUV encode, compress from
  YUV, decompress to YUV, and YUV decode.  A <code>YUVImage</code> instance
@@ -106,230 +140,205 @@ extends java.lang.Object</pre>
  operations and as the source image for compress-from-YUV and YUV decode
  operations.
  <p>
- Technically, the JPEG format uses the YCbCr colorspace (which technically is
- not a "colorspace" but rather 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.
+ 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.
  <p>
  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 (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
- 4:1:1, 1 in the case of 4:4:4 or grayscale.)  Similarly, the luminance plane
- height is the image height padded to the nearest multiple of the vertical
- subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
- or grayscale.)  The chrominance plane width is equal to the luminance plane
- width divided by the horizontal subsampling factor, and the chrominance
- plane height is equal to the luminance plane height divided by the vertical
- subsampling factor.
+ subsampling factor (1 in the case of 4:4:4, grayscale, 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 YUVImage methods.  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.
  <p>
  For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
  used, then the luminance plane would be 36 x 35 bytes, and each of the
- chrominance planes would be 18 x 35 bytes.  If you specify a line padding of
- 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
- each of the chrominance planes would be 20 x 35 bytes.</div>
+ 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.</div>
 </li>
 </ul>
 </div>
 <div class="summary">
 <ul class="blockList">
 <li class="blockList">
-<!-- =========== FIELD SUMMARY =========== -->
-<ul class="blockList">
-<li class="blockList"><a name="field_summary">
-<!--   -->
-</a>
-<h3>Field Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Field Summary table, listing fields, and an explanation">
-<caption><span>Fields</span><span class="tabEnd">&nbsp;</span></caption>
-<tr>
-<th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Field and Description</th>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected long</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#handle">handle</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvHeight">yuvHeight</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected int[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvOffsets">yuvOffsets</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvPad">yuvPad</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected byte[][]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvPlanes">yuvPlanes</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvStrides">yuvStrides</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="altColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvSubsamp">yuvSubsamp</a></strong></code>&nbsp;</td>
-</tr>
-<tr class="rowColor">
-<td class="colFirst"><code>protected int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#yuvWidth">yuvWidth</a></strong></code>&nbsp;</td>
-</tr>
-</table>
-</li>
-</ul>
 <!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_summary">
+<li class="blockList"><a id="constructor.summary">
 <!--   -->
 </a>
 <h3>Constructor Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Constructor Summary table, listing constructors, and an explanation">
+<table class="memberSummary">
 <caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
-<th class="colOne" scope="col">Constructor and Description</th>
+<th class="colFirst" scope="col">Constructor</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(byte[][],%20int[],%20int,%20int[],%20int,%20int)">YUVImage</a></strong>(byte[][]&nbsp;planes,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D%5B%5D,int%5B%5D,int,int%5B%5D,int,int)">YUVImage</a></span>&#8203;(byte[][]&nbsp;planes,
         int[]&nbsp;offsets,
         int&nbsp;width,
         int[]&nbsp;strides,
         int&nbsp;height,
-        int&nbsp;subsamp)</code>
+        int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Create a new <code>YUVImage</code> instance from a set of existing image
  planes.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(byte[],%20int,%20int,%20int,%20int)">YUVImage</a></strong>(byte[]&nbsp;yuvImage,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(byte%5B%5D,int,int,int,int)">YUVImage</a></span>&#8203;(byte[]&nbsp;yuvImage,
         int&nbsp;width,
-        int&nbsp;pad,
+        int&nbsp;align,
         int&nbsp;height,
-        int&nbsp;subsamp)</code>
-<div class="block">Create a new <code>YUVImage</code> instance from an existing unified image
+        int&nbsp;subsamp)</code></th>
+<td class="colLast">
+<div class="block">Create a new <code>YUVImage</code> instance from an existing unified
  buffer.</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(int,%20int[],%20int,%20int)">YUVImage</a></strong>(int&nbsp;width,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int%5B%5D,int,int)">YUVImage</a></span>&#8203;(int&nbsp;width,
         int[]&nbsp;strides,
         int&nbsp;height,
-        int&nbsp;subsamp)</code>
+        int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Create a new <code>YUVImage</code> instance backed by separate image
  planes, and allocate memory for the image planes.</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colOne"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#YUVImage(int,%20int,%20int,%20int)">YUVImage</a></strong>(int&nbsp;width,
-        int&nbsp;pad,
+<th class="colConstructorName" scope="row"><code><span class="memberNameLink"><a href="#%3Cinit%3E(int,int,int,int)">YUVImage</a></span>&#8203;(int&nbsp;width,
+        int&nbsp;align,
         int&nbsp;height,
-        int&nbsp;subsamp)</code>
-<div class="block">Create a new <code>YUVImage</code> instance backed by a unified image
- buffer, and allocate memory for the image buffer.</div>
+        int&nbsp;subsamp)</code></th>
+<td class="colLast">
+<div class="block">Create a new <code>YUVImage</code> instance backed by a unified buffer,
+ and allocate memory for the buffer.</div>
 </td>
 </tr>
 </table>
 </li>
 </ul>
+</section>
 <!-- ========== METHOD SUMMARY =========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_summary">
+<li class="blockList"><a id="method.summary">
 <!--   -->
 </a>
 <h3>Method Summary</h3>
-<table class="overviewSummary" border="0" cellpadding="3" cellspacing="0" summary="Method Summary table, listing methods, and an explanation">
-<caption><span>Methods</span><span class="tabEnd">&nbsp;</span></caption>
+<table class="memberSummary">
+<caption><span id="t0" class="activeTableTab"><span>All Methods</span><span class="tabEnd">&nbsp;</span></span><span id="t2" class="tableTab"><span><a href="javascript:show(2);">Instance Methods</a></span><span class="tabEnd">&nbsp;</span></span><span id="t4" class="tableTab"><span><a href="javascript:show(8);">Concrete Methods</a></span><span class="tabEnd">&nbsp;</span></span></caption>
 <tr>
 <th class="colFirst" scope="col">Modifier and Type</th>
-<th class="colLast" scope="col">Method and Description</th>
+<th class="colSecond" scope="col">Method</th>
+<th class="colLast" scope="col">Description</th>
 </tr>
-<tr class="altColor">
+<tr id="i0" class="altColor">
 <td class="colFirst"><code>byte[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getBuf()">getBuf</a></strong>()</code>
-<div class="block">Returns the YUV image buffer (if this image is stored in a unified
- buffer rather than separate image planes.)</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getBuf()">getBuf</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns the YUV buffer (if this image is stored in a unified buffer rather
+ than separate image planes.)</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i1" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getHeight()">getHeight</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getHeight()">getHeight</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the height of the YUV image (or subregion.)</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i2" class="altColor">
 <td class="colFirst"><code>int[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getOffsets()">getOffsets</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getOffsets()">getOffsets</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the offsets (in bytes) of each plane within the planes of a larger
  YUV image.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i3" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getPad()">getPad</a></strong>()</code>
-<div class="block">Returns the line padding used in the YUV image buffer (if this image is
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getPad()">getPad</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns the row alignment (in bytes) of the YUV buffer (if this image is
  stored in a unified buffer rather than separate image planes.)</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i4" class="altColor">
 <td class="colFirst"><code>byte[][]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getPlanes()">getPlanes</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getPlanes()">getPlanes</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the YUV image planes.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i5" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getSize()">getSize</a></strong>()</code>
-<div class="block">Returns the size (in bytes) of the YUV image buffer (if this image is
- stored in a unified buffer rather than separate image planes.)</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getSize()">getSize</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns the size (in bytes) of the YUV buffer (if this image is stored in
+ a unified buffer rather than separate image planes.)</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i6" class="altColor">
 <td class="colFirst"><code>int[]</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getStrides()">getStrides</a></strong>()</code>
-<div class="block">Returns the number of bytes per line of each plane in the YUV image.</div>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getStrides()">getStrides</a></span>()</code></th>
+<td class="colLast">
+<div class="block">Returns the number of bytes per row of each plane in the YUV image.</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i7" class="rowColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getSubsamp()">getSubsamp</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getSubsamp()">getSubsamp</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the level of chrominance subsampling used in the YUV image.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i8" class="altColor">
 <td class="colFirst"><code>int</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#getWidth()">getWidth</a></strong>()</code>
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#getWidth()">getWidth</a></span>()</code></th>
+<td class="colLast">
 <div class="block">Returns the width of the YUV image (or subregion.)</div>
 </td>
 </tr>
-<tr class="rowColor">
+<tr id="i9" class="rowColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte[][],%20int[],%20int,%20int[],%20int,%20int)">setBuf</a></strong>(byte[][]&nbsp;planes,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setBuf(byte%5B%5D%5B%5D,int%5B%5D,int,int%5B%5D,int,int)">setBuf</a></span>&#8203;(byte[][]&nbsp;planes,
       int[]&nbsp;offsets,
       int&nbsp;width,
       int[]&nbsp;strides,
       int&nbsp;height,
-      int&nbsp;subsamp)</code>
+      int&nbsp;subsamp)</code></th>
+<td class="colLast">
 <div class="block">Assign a set of image planes to this <code>YUVImage</code> instance.</div>
 </td>
 </tr>
-<tr class="altColor">
+<tr id="i10" class="altColor">
 <td class="colFirst"><code>void</code></td>
-<td class="colLast"><code><strong><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html#setBuf(byte[],%20int,%20int,%20int,%20int)">setBuf</a></strong>(byte[]&nbsp;yuvImage,
+<th class="colSecond" scope="row"><code><span class="memberNameLink"><a href="#setBuf(byte%5B%5D,int,int,int,int)">setBuf</a></span>&#8203;(byte[]&nbsp;yuvImage,
       int&nbsp;width,
-      int&nbsp;pad,
+      int&nbsp;align,
       int&nbsp;height,
-      int&nbsp;subsamp)</code>
-<div class="block">Assign a unified image buffer to this <code>YUVImage</code> instance.</div>
+      int&nbsp;subsamp)</code></th>
+<td class="colLast">
+<div class="block">Assign a unified buffer to this <code>YUVImage</code> instance.</div>
 </td>
 </tr>
 </table>
 <ul class="blockList">
-<li class="blockList"><a name="methods_inherited_from_class_java.lang.Object">
+<li class="blockList"><a id="methods.inherited.from.class.java.lang.Object">
 <!--   -->
 </a>
 <h3>Methods inherited from class&nbsp;java.lang.Object</h3>
@@ -337,380 +346,383 @@ extends java.lang.Object</pre>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 <div class="details">
 <ul class="blockList">
 <li class="blockList">
-<!-- ============ FIELD DETAIL =========== -->
-<ul class="blockList">
-<li class="blockList"><a name="field_detail">
-<!--   -->
-</a>
-<h3>Field Detail</h3>
-<a name="handle">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>handle</h4>
-<pre>protected&nbsp;long handle</pre>
-</li>
-</ul>
-<a name="yuvPlanes">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvPlanes</h4>
-<pre>protected&nbsp;byte[][] yuvPlanes</pre>
-</li>
-</ul>
-<a name="yuvOffsets">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvOffsets</h4>
-<pre>protected&nbsp;int[] yuvOffsets</pre>
-</li>
-</ul>
-<a name="yuvStrides">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvStrides</h4>
-<pre>protected&nbsp;int[] yuvStrides</pre>
-</li>
-</ul>
-<a name="yuvPad">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvPad</h4>
-<pre>protected&nbsp;int yuvPad</pre>
-</li>
-</ul>
-<a name="yuvWidth">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvWidth</h4>
-<pre>protected&nbsp;int yuvWidth</pre>
-</li>
-</ul>
-<a name="yuvHeight">
-<!--   -->
-</a>
-<ul class="blockList">
-<li class="blockList">
-<h4>yuvHeight</h4>
-<pre>protected&nbsp;int yuvHeight</pre>
-</li>
-</ul>
-<a name="yuvSubsamp">
-<!--   -->
-</a>
-<ul class="blockListLast">
-<li class="blockList">
-<h4>yuvSubsamp</h4>
-<pre>protected&nbsp;int yuvSubsamp</pre>
-</li>
-</ul>
-</li>
-</ul>
 <!-- ========= CONSTRUCTOR DETAIL ======== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="constructor_detail">
+<li class="blockList"><a id="constructor.detail">
 <!--   -->
 </a>
 <h3>Constructor Detail</h3>
-<a name="YUVImage(int, int[], int, int)">
+<a id="&lt;init&gt;(int,int[],int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>YUVImage</h4>
-<pre>public&nbsp;YUVImage(int&nbsp;width,
-        int[]&nbsp;strides,
-        int&nbsp;height,
-        int&nbsp;subsamp)</pre>
+<pre>public&nbsp;YUVImage&#8203;(int&nbsp;width,
+                int[]&nbsp;strides,
+                int&nbsp;height,
+                int&nbsp;subsamp)</pre>
 <div class="block">Create a new <code>YUVImage</code> instance backed by separate image
  planes, and allocate memory for the image planes.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>width</code> - width (in pixels) of the YUV image</dd><dd><code>strides</code> - an array of integers, each specifying the number of bytes
- per line in the corresponding plane of the YUV image.  Setting the stride
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>width</code> - width (in pixels) of the YUV image</dd>
+<dd><code>strides</code> - 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
- <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
+ <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
  strides for all planes will be set to their respective plane widths.  When
  using this constructor, the stride for each plane must be equal to or
- greater than the plane width.</dd><dd><code>height</code> - height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling to be used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
+ greater than the plane width.</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling to be used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
 </li>
 </ul>
-<a name="YUVImage(int, int, int, int)">
+<a id="&lt;init&gt;(int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>YUVImage</h4>
-<pre>public&nbsp;YUVImage(int&nbsp;width,
-        int&nbsp;pad,
-        int&nbsp;height,
-        int&nbsp;subsamp)</pre>
-<div class="block">Create a new <code>YUVImage</code> instance backed by a unified image
- buffer, and allocate memory for the image buffer.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>width</code> - width (in pixels) of the YUV image</dd><dd><code>pad</code> - Each line of each plane in the YUV image buffer will be padded
- to this number of bytes (must be a power of 2.)</dd><dd><code>height</code> - height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling to be used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
-</li>
-</ul>
-<a name="YUVImage(byte[][], int[], int, int[], int, int)">
+<pre>public&nbsp;YUVImage&#8203;(int&nbsp;width,
+                int&nbsp;align,
+                int&nbsp;height,
+                int&nbsp;subsamp)</pre>
+<div class="block">Create a new <code>YUVImage</code> instance backed by a unified buffer,
+ and allocate memory for the buffer.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>width</code> - width (in pixels) of the YUV image</dd>
+<dd><code>align</code> - row alignment (in bytes) of the YUV image (must be a power of
+ 2.)  Setting this parameter to n specifies that each row in each plane of
+ the YUV image will be padded to the nearest multiple of n bytes
+ (1 = unpadded.)</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling to be used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
+</li>
+</ul>
+<a id="&lt;init&gt;(byte[][],int[],int,int[],int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>YUVImage</h4>
-<pre>public&nbsp;YUVImage(byte[][]&nbsp;planes,
-        int[]&nbsp;offsets,
-        int&nbsp;width,
-        int[]&nbsp;strides,
-        int&nbsp;height,
-        int&nbsp;subsamp)</pre>
+<pre>public&nbsp;YUVImage&#8203;(byte[][]&nbsp;planes,
+                int[]&nbsp;offsets,
+                int&nbsp;width,
+                int[]&nbsp;strides,
+                int&nbsp;height,
+                int&nbsp;subsamp)</pre>
 <div class="block">Create a new <code>YUVImage</code> instance from a set of existing image
  planes.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>planes</code> - an array of buffers representing the Y, U (Cb), and V (Cr)
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>planes</code> - an array of buffers representing the Y, U (Cb), and V (Cr)
  image planes (or just the Y plane, if the image is grayscale.)   These
  planes can be contiguous or non-contiguous in memory.  Plane
  <code>i</code> should be at least <code>offsets[i] +
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#planeSizeYUV(int,%20int,%20int,%20int,%20int)"><code>TJ.planeSizeYUV</code></a>(i, width, strides[i], height, subsamp)</code>
- bytes in size.</dd><dd><code>offsets</code> - If this <code>YUVImage</code> instance represents a
+ <a href="TJ.html#planeSizeYUV(int,int,int,int,int)"><code>TJ.planeSizeYUV</code></a>(i, width, strides[i], height, subsamp)</code>
+ bytes in size.</dd>
+<dd><code>offsets</code> - If this <code>YUVImage</code> instance represents a
  subregion of a larger image, then <code>offsets[i]</code> specifies the
  offset (in bytes) of the subregion within plane <code>i</code> of the
  larger image.  Setting this to null is the same as setting the offsets for
- all planes to 0.</dd><dd><code>width</code> - width (in pixels) of the new YUV image (or subregion)</dd><dd><code>strides</code> - an array of integers, each specifying the number of bytes
- per line in the corresponding plane of the YUV image.  Setting the stride
+ all planes to 0.</dd>
+<dd><code>width</code> - width (in pixels) of the new YUV image (or subregion)</dd>
+<dd><code>strides</code> - 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
- <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
+ <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
  strides for all planes will be set to their respective plane widths.  You
- can adjust the strides in order to add an arbitrary amount of line padding
+ can adjust the strides in order to add an arbitrary amount of row padding
  to each plane or to specify that this <code>YUVImage</code> instance is a
  subregion of a larger image (in which case, <code>strides[i]</code> should
- be set to the plane width of plane <code>i</code> in the larger image.)</dd><dd><code>height</code> - height (in pixels) of the new YUV image (or subregion)</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
+ be set to the plane width of plane <code>i</code> in the larger image.)</dd>
+<dd><code>height</code> - height (in pixels) of the new YUV image (or subregion)</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
 </li>
 </ul>
-<a name="YUVImage(byte[], int, int, int, int)">
+<a id="&lt;init&gt;(byte[],int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>YUVImage</h4>
-<pre>public&nbsp;YUVImage(byte[]&nbsp;yuvImage,
-        int&nbsp;width,
-        int&nbsp;pad,
-        int&nbsp;height,
-        int&nbsp;subsamp)</pre>
-<div class="block">Create a new <code>YUVImage</code> instance from an existing unified image
+<pre>public&nbsp;YUVImage&#8203;(byte[]&nbsp;yuvImage,
+                int&nbsp;width,
+                int&nbsp;align,
+                int&nbsp;height,
+                int&nbsp;subsamp)</pre>
+<div class="block">Create a new <code>YUVImage</code> instance from an existing unified
  buffer.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>yuvImage</code> - image buffer that contains or will contain YUV planar
- image data.  Use <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>TJ.bufSizeYUV(int, int, int, int)</code></a> to determine the minimum size for
- this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
- sequentially in the buffer (see <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a> for a description
- of the image format.)</dd><dd><code>width</code> - width (in pixels) of the YUV image</dd><dd><code>pad</code> - the line padding used in the YUV image buffer.  For
- instance, if each line in each plane of the buffer is padded to the
- nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.</dd><dd><code>height</code> - height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
-</li>
-</ul>
-</li>
-</ul>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>yuvImage</code> - buffer that contains or will receive a unified planar YUV
+ image.  Use <a href="TJ.html#bufSizeYUV(int,int,int,int)"><code>TJ.bufSizeYUV()</code></a> to determine the minimum
+ size for this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
+ sequentially in the buffer.  (See <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a> for a description
+ of the image format.)</dd>
+<dd><code>width</code> - width (in pixels) of the YUV image</dd>
+<dd><code>align</code> - row alignment (in bytes) of the YUV image (must be a power of
+ 2.)  Setting this parameter to n specifies that each row in each plane of
+ the YUV image will be padded to the nearest multiple of n bytes
+ (1 = unpadded.)</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
+</li>
+</ul>
+</li>
+</ul>
+</section>
 <!-- ============ METHOD DETAIL ========== -->
+<section>
 <ul class="blockList">
-<li class="blockList"><a name="method_detail">
+<li class="blockList"><a id="method.detail">
 <!--   -->
 </a>
 <h3>Method Detail</h3>
-<a name="setBuf(byte[][], int[], int, int[], int, int)">
+<a id="setBuf(byte[][],int[],int,int[],int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>setBuf</h4>
-<pre>public&nbsp;void&nbsp;setBuf(byte[][]&nbsp;planes,
-          int[]&nbsp;offsets,
-          int&nbsp;width,
-          int[]&nbsp;strides,
-          int&nbsp;height,
-          int&nbsp;subsamp)</pre>
+<pre class="methodSignature">public&nbsp;void&nbsp;setBuf&#8203;(byte[][]&nbsp;planes,
+                   int[]&nbsp;offsets,
+                   int&nbsp;width,
+                   int[]&nbsp;strides,
+                   int&nbsp;height,
+                   int&nbsp;subsamp)</pre>
 <div class="block">Assign a set of image planes to this <code>YUVImage</code> instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>planes</code> - an array of buffers representing the Y, U (Cb), and V (Cr)
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>planes</code> - an array of buffers representing the Y, U (Cb), and V (Cr)
  image planes (or just the Y plane, if the image is grayscale.)  These
  planes can be contiguous or non-contiguous in memory.  Plane
  <code>i</code> should be at least <code>offsets[i] +
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#planeSizeYUV(int,%20int,%20int,%20int,%20int)"><code>TJ.planeSizeYUV</code></a>(i, width, strides[i], height, subsamp)</code>
- bytes in size.</dd><dd><code>offsets</code> - If this <code>YUVImage</code> instance represents a
+ <a href="TJ.html#planeSizeYUV(int,int,int,int,int)"><code>TJ.planeSizeYUV</code></a>(i, width, strides[i], height, subsamp)</code>
+ bytes in size.</dd>
+<dd><code>offsets</code> - If this <code>YUVImage</code> instance represents a
  subregion of a larger image, then <code>offsets[i]</code> specifies the
  offset (in bytes) of the subregion within plane <code>i</code> of the
  larger image.  Setting this to null is the same as setting the offsets for
- all planes to 0.</dd><dd><code>width</code> - width (in pixels) of the YUV image (or subregion)</dd><dd><code>strides</code> - an array of integers, each specifying the number of bytes
- per line in the corresponding plane of the YUV image.  Setting the stride
+ all planes to 0.</dd>
+<dd><code>width</code> - width (in pixels) of the YUV image (or subregion)</dd>
+<dd><code>strides</code> - 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
- <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
+ <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a>.)  If <code>strides</code> is null, then the
  strides for all planes will be set to their respective plane widths.  You
- can adjust the strides in order to add an arbitrary amount of line padding
- to each plane or to specify that this <code>YUVImage</code> image is a
+ can adjust the strides in order to add an arbitrary amount of row padding
+ to each plane or to specify that this <code>YUVImage</code> instance is a
  subregion of a larger image (in which case, <code>strides[i]</code> should
- be set to the plane width of plane <code>i</code> in the larger image.)</dd><dd><code>height</code> - height (in pixels) of the YUV image (or subregion)</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
+ be set to the plane width of plane <code>i</code> in the larger image.)</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image (or subregion)</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
 </li>
 </ul>
-<a name="setBuf(byte[], int, int, int, int)">
+<a id="setBuf(byte[],int,int,int,int)">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>setBuf</h4>
-<pre>public&nbsp;void&nbsp;setBuf(byte[]&nbsp;yuvImage,
-          int&nbsp;width,
-          int&nbsp;pad,
-          int&nbsp;height,
-          int&nbsp;subsamp)</pre>
-<div class="block">Assign a unified image buffer to this <code>YUVImage</code> instance.</div>
-<dl><dt><span class="strong">Parameters:</span></dt><dd><code>yuvImage</code> - image buffer that contains or will contain YUV planar
- image data.  Use <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#bufSizeYUV(int,%20int,%20int,%20int)"><code>TJ.bufSizeYUV(int, int, int, int)</code></a> to determine the minimum size for
- this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
- sequentially in the buffer (see <a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a> for a description
- of the image format.)</dd><dd><code>width</code> - width (in pixels) of the YUV image</dd><dd><code>pad</code> - the line padding used in the YUV image buffer.  For
- instance, if each line in each plane of the buffer is padded to the
- nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.</dd><dd><code>height</code> - height (in pixels) of the YUV image</dd><dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
- image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
-</li>
-</ul>
-<a name="getWidth()">
+<pre class="methodSignature">public&nbsp;void&nbsp;setBuf&#8203;(byte[]&nbsp;yuvImage,
+                   int&nbsp;width,
+                   int&nbsp;align,
+                   int&nbsp;height,
+                   int&nbsp;subsamp)</pre>
+<div class="block">Assign a unified buffer to this <code>YUVImage</code> instance.</div>
+<dl>
+<dt><span class="paramLabel">Parameters:</span></dt>
+<dd><code>yuvImage</code> - buffer that contains or will receive a unified planar YUV
+ image.  Use <a href="TJ.html#bufSizeYUV(int,int,int,int)"><code>TJ.bufSizeYUV()</code></a> to determine the minimum
+ size for this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
+ sequentially in the buffer.  (See <a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><code>above</code></a> for a description
+ of the image format.)</dd>
+<dd><code>width</code> - width (in pixels) of the YUV image</dd>
+<dd><code>align</code> - row alignment (in bytes) of the YUV image (must be a power of
+ 2.)  Setting this parameter to n specifies that each row in each plane of
+ the YUV image will be padded to the nearest multiple of n bytes
+ (1 = unpadded.)</dd>
+<dd><code>height</code> - height (in pixels) of the YUV image</dd>
+<dd><code>subsamp</code> - the level of chrominance subsampling used in the YUV
+ image (one of <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd>
+</dl>
+</li>
+</ul>
+<a id="getWidth()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getWidth</h4>
-<pre>public&nbsp;int&nbsp;getWidth()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getWidth()</pre>
 <div class="block">Returns the width of the YUV image (or subregion.)</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the width of the YUV image (or subregion)</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the width of the YUV image (or subregion)</dd>
+</dl>
 </li>
 </ul>
-<a name="getHeight()">
+<a id="getHeight()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getHeight</h4>
-<pre>public&nbsp;int&nbsp;getHeight()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getHeight()</pre>
 <div class="block">Returns the height of the YUV image (or subregion.)</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the height of the YUV image (or subregion)</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the height of the YUV image (or subregion)</dd>
+</dl>
 </li>
 </ul>
-<a name="getPad()">
+<a id="getPad()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getPad</h4>
-<pre>public&nbsp;int&nbsp;getPad()</pre>
-<div class="block">Returns the line padding used in the YUV image buffer (if this image is
+<pre class="methodSignature">public&nbsp;int&nbsp;getPad()</pre>
+<div class="block">Returns the row alignment (in bytes) of the YUV buffer (if this image is
  stored in a unified buffer rather than separate image planes.)</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the line padding used in the YUV image buffer</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the row alignment of the YUV buffer</dd>
+</dl>
 </li>
 </ul>
-<a name="getStrides()">
+<a id="getStrides()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getStrides</h4>
-<pre>public&nbsp;int[]&nbsp;getStrides()</pre>
-<div class="block">Returns the number of bytes per line of each plane in the YUV image.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the number of bytes per line of each plane in the YUV image</dd></dl>
+<pre class="methodSignature">public&nbsp;int[]&nbsp;getStrides()</pre>
+<div class="block">Returns the number of bytes per row of each plane in the YUV image.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the number of bytes per row of each plane in the YUV image</dd>
+</dl>
 </li>
 </ul>
-<a name="getOffsets()">
+<a id="getOffsets()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getOffsets</h4>
-<pre>public&nbsp;int[]&nbsp;getOffsets()</pre>
+<pre class="methodSignature">public&nbsp;int[]&nbsp;getOffsets()</pre>
 <div class="block">Returns the offsets (in bytes) of each plane within the planes of a larger
  YUV image.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the offsets (in bytes) of each plane within the planes of a larger
- YUV image</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the offsets (in bytes) of each plane within the planes of a larger
+ YUV image</dd>
+</dl>
 </li>
 </ul>
-<a name="getSubsamp()">
+<a id="getSubsamp()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getSubsamp</h4>
-<pre>public&nbsp;int&nbsp;getSubsamp()</pre>
+<pre class="methodSignature">public&nbsp;int&nbsp;getSubsamp()</pre>
 <div class="block">Returns the level of chrominance subsampling used in the YUV image.  See
- <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the level of chrominance subsampling used in the YUV image</dd></dl>
+ <a href="TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>.</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the level of chrominance subsampling used in the YUV image</dd>
+</dl>
 </li>
 </ul>
-<a name="getPlanes()">
+<a id="getPlanes()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getPlanes</h4>
-<pre>public&nbsp;byte[][]&nbsp;getPlanes()</pre>
+<pre class="methodSignature">public&nbsp;byte[][]&nbsp;getPlanes()</pre>
 <div class="block">Returns the YUV image planes.  If the image is stored in a unified buffer,
  then all image planes will point to that buffer.</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the YUV image planes</dd></dl>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the YUV image planes</dd>
+</dl>
 </li>
 </ul>
-<a name="getBuf()">
+<a id="getBuf()">
 <!--   -->
 </a>
 <ul class="blockList">
 <li class="blockList">
 <h4>getBuf</h4>
-<pre>public&nbsp;byte[]&nbsp;getBuf()</pre>
-<div class="block">Returns the YUV image buffer (if this image is stored in a unified
- buffer rather than separate image planes.)</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the YUV image buffer</dd></dl>
+<pre class="methodSignature">public&nbsp;byte[]&nbsp;getBuf()</pre>
+<div class="block">Returns the YUV buffer (if this image is stored in a unified buffer rather
+ than separate image planes.)</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the YUV buffer</dd>
+</dl>
 </li>
 </ul>
-<a name="getSize()">
+<a id="getSize()">
 <!--   -->
 </a>
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getSize</h4>
-<pre>public&nbsp;int&nbsp;getSize()</pre>
-<div class="block">Returns the size (in bytes) of the YUV image buffer (if this image is
- stored in a unified buffer rather than separate image planes.)</div>
-<dl><dt><span class="strong">Returns:</span></dt><dd>the size (in bytes) of the YUV image buffer</dd></dl>
+<pre class="methodSignature">public&nbsp;int&nbsp;getSize()</pre>
+<div class="block">Returns the size (in bytes) of the YUV buffer (if this image is stored in
+ a unified buffer rather than separate image planes.)</div>
+<dl>
+<dt><span class="returnLabel">Returns:</span></dt>
+<dd>the size (in bytes) of the YUV buffer</dd>
+</dl>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
 </div>
+</main>
 <!-- ========= END OF CLASS DATA ========= -->
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li class="navBarCell1Rev">Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
@@ -719,16 +731,8 @@ extends java.lang.Object</pre>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Prev Class</span></a></li>
-<li>Next Class</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/YUVImage.html" target="_top">Frames</a></li>
-<li><a href="YUVImage.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
@@ -741,25 +745,30 @@ extends java.lang.Object</pre>
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
 <div>
 <ul class="subNavList">
 <li>Summary:&nbsp;</li>
 <li>Nested&nbsp;|&nbsp;</li>
-<li><a href="#field_summary">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_summary">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_summary">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.summary">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.summary">Method</a></li>
 </ul>
 <ul class="subNavList">
 <li>Detail:&nbsp;</li>
-<li><a href="#field_detail">Field</a>&nbsp;|&nbsp;</li>
-<li><a href="#constructor_detail">Constr</a>&nbsp;|&nbsp;</li>
-<li><a href="#method_detail">Method</a></li>
+<li>Field&nbsp;|&nbsp;</li>
+<li><a href="#constructor.detail">Constr</a>&nbsp;|&nbsp;</li>
+<li><a href="#method.detail">Method</a></li>
 </ul>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
deleted file mode 100644 (file)
index 08a8bf8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<!-- NewPage -->
-<html lang="en">
-<head>
-<title>org.libjpegturbo.turbojpeg</title>
-<link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
-</head>
-<body>
-<h1 class="bar"><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html" target="classFrame">org.libjpegturbo.turbojpeg</a></h1>
-<div class="indexContainer">
-<h2 title="Interfaces">Interfaces</h2>
-<ul title="Interfaces">
-<li><a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg" target="classFrame"><i>TJCustomFilter</i></a></li>
-</ul>
-<h2 title="Classes">Classes</h2>
-<ul title="Classes">
-<li><a href="TJ.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJ</a></li>
-<li><a href="TJCompressor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJCompressor</a></li>
-<li><a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJDecompressor</a></li>
-<li><a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJScalingFactor</a></li>
-<li><a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJTransform</a></li>
-<li><a href="TJTransformer.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJTransformer</a></li>
-<li><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">YUVImage</a></li>
-</ul>
-<h2 title="Exceptions">Exceptions</h2>
-<ul title="Exceptions">
-<li><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg" target="classFrame">TJException</a></li>
-</ul>
-</div>
-</body>
-</html>
index dedcce5..0a027c3 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>org.libjpegturbo.turbojpeg</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li class="navBarCell1Rev">Package</li>
 <li>Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev Package</li>
-<li>Next Package</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/package-summary.html" target="_top">Frames</a></li>
-<li><a href="package-summary.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 title="Package" class="title">Package&nbsp;org.libjpegturbo.turbojpeg</h1>
 </div>
 <div class="contentContainer">
 <ul class="blockList">
 <li class="blockList">
-<table class="packageSummary" border="0" cellpadding="3" cellspacing="0" summary="Interface Summary table, listing interfaces, and an explanation">
+<table class="typeSummary">
 <caption><span>Interface Summary</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Interface</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></td>
+<th class="colFirst" scope="row"><a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a></th>
 <td class="colLast">
 <div class="block">Custom filter callback interface</div>
 </td>
 </table>
 </li>
 <li class="blockList">
-<table class="packageSummary" border="0" cellpadding="3" cellspacing="0" summary="Class Summary table, listing classes, and an explanation">
+<table class="typeSummary">
 <caption><span>Class Summary</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Class</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></td>
+<th class="colFirst" scope="row"><a href="TJ.html" title="class in org.libjpegturbo.turbojpeg">TJ</a></th>
 <td class="colLast">
 <div class="block">TurboJPEG utility class (cannot be instantiated)</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></td>
+<th class="colFirst" scope="row"><a href="TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</a></th>
 <td class="colLast">
 <div class="block">TurboJPEG compressor</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></td>
+<th class="colFirst" scope="row"><a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</a></th>
 <td class="colLast">
 <div class="block">TurboJPEG decompressor</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></td>
+<th class="colFirst" scope="row"><a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg">TJScalingFactor</a></th>
 <td class="colLast">
 <div class="block">Fractional scaling factor</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></td>
+<th class="colFirst" scope="row"><a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></th>
 <td class="colLast">
 <div class="block">Lossless transform parameters</div>
 </td>
 </tr>
 <tr class="rowColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></td>
+<th class="colFirst" scope="row"><a href="TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></th>
 <td class="colLast">
 <div class="block">TurboJPEG lossless transformer</div>
 </td>
 </tr>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></td>
+<th class="colFirst" scope="row"><a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg">YUVImage</a></th>
 <td class="colLast">
-<div class="block">This class encapsulates a YUV planar image and the metadata
+<div class="block">This class encapsulates a planar YUV image and the metadata
  associated with it.</div>
 </td>
 </tr>
 </table>
 </li>
 <li class="blockList">
-<table class="packageSummary" border="0" cellpadding="3" cellspacing="0" summary="Exception Summary table, listing exceptions, and an explanation">
+<table class="typeSummary">
 <caption><span>Exception Summary</span><span class="tabEnd">&nbsp;</span></caption>
 <tr>
 <th class="colFirst" scope="col">Exception</th>
 </tr>
 <tbody>
 <tr class="altColor">
-<td class="colFirst"><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></td>
+<th class="colFirst" scope="row"><a href="TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></th>
 <td class="colLast">&nbsp;</td>
 </tr>
 </tbody>
 </li>
 </ul>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li class="navBarCell1Rev">Package</li>
 <li>Class</li>
 <li><a href="package-tree.html">Tree</a></li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev Package</li>
-<li>Next Package</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/package-summary.html" target="_top">Frames</a></li>
-<li><a href="package-summary.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 5f0f8c3..ca8d36a 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>org.libjpegturbo.turbojpeg Class Hierarchy</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="../../../jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="../../../script.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="../../../jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="../../../jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="../../../jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "../../../";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li>Class</li>
 <li class="navBarCell1Rev">Tree</li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/package-tree.html" target="_top">Frames</a></li>
-<li><a href="package-tree.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 class="title">Hierarchy For Package org.libjpegturbo.turbojpeg</h1>
 </div>
 <div class="contentContainer">
+<section>
 <h2 title="Class Hierarchy">Class Hierarchy</h2>
 <ul>
-<li type="circle">java.lang.Object
+<li class="circle">java.lang.Object
 <ul>
-<li type="circle">java.awt.geom.RectangularShape (implements java.lang.Cloneable, java.awt.Shape)
+<li class="circle">java.awt.geom.RectangularShape (implements java.lang.Cloneable, java.awt.Shape)
 <ul>
-<li type="circle">java.awt.geom.Rectangle2D
+<li class="circle">java.awt.geom.Rectangle2D
 <ul>
-<li type="circle">java.awt.Rectangle (implements java.io.Serializable, java.awt.Shape)
+<li class="circle">java.awt.Rectangle (implements java.io.Serializable, java.awt.Shape)
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransform</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransform</span></a></li>
 </ul>
 </li>
 </ul>
 </li>
 </ul>
 </li>
-<li type="circle">java.lang.Throwable (implements java.io.Serializable)
+<li class="circle">java.lang.Throwable (implements java.io.Serializable)
 <ul>
-<li type="circle">java.lang.Exception
+<li class="circle">java.lang.Exception
 <ul>
-<li type="circle">java.io.IOException
+<li class="circle">java.io.IOException
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJException</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJException</span></a></li>
 </ul>
 </li>
 </ul>
 </li>
 </ul>
 </li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJ</span></a></li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJCompressor</span></a> (implements java.io.Closeable)</li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJDecompressor</span></a> (implements java.io.Closeable)
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJ</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCompressor</span></a> (implements java.io.Closeable)</li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJDecompressor</span></a> (implements java.io.Closeable)
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransformer</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransformer</span></a></li>
 </ul>
 </li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJScalingFactor</span></a></li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">YUVImage</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJScalingFactor</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">YUVImage</span></a></li>
 </ul>
 </li>
 </ul>
+</section>
+<section>
 <h2 title="Interface Hierarchy">Interface Hierarchy</h2>
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="../../../org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">TJCustomFilter</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCustomFilter</span></a></li>
 </ul>
+</section>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="../../../org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li><a href="package-summary.html">Package</a></li>
 <li>Class</li>
 <li class="navBarCell1Rev">Tree</li>
 <li><a href="../../../deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="../../../index.html?org/libjpegturbo/turbojpeg/package-tree.html" target="_top">Frames</a></li>
-<li><a href="package-tree.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="../../../allclasses-noframe.html">All Classes</a></li>
+<li><a href="../../../allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index b659995..d2d6d53 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Class Hierarchy</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Package</li>
 <li>Class</li>
 <li class="navBarCell1Rev">Tree</li>
 <li><a href="deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?overview-tree.html" target="_top">Frames</a></li>
-<li><a href="overview-tree.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 class="title">Hierarchy For All Packages</h1>
-<span class="strong">Package Hierarchies:</span>
+<span class="packageHierarchyLabel">Package Hierarchies:</span>
 <ul class="horizontal">
 <li><a href="org/libjpegturbo/turbojpeg/package-tree.html">org.libjpegturbo.turbojpeg</a></li>
 </ul>
 </div>
 <div class="contentContainer">
+<section>
 <h2 title="Class Hierarchy">Class Hierarchy</h2>
 <ul>
-<li type="circle">java.lang.Object
+<li class="circle">java.lang.Object
 <ul>
-<li type="circle">java.awt.geom.RectangularShape (implements java.lang.Cloneable, java.awt.Shape)
+<li class="circle">java.awt.geom.RectangularShape (implements java.lang.Cloneable, java.awt.Shape)
 <ul>
-<li type="circle">java.awt.geom.Rectangle2D
+<li class="circle">java.awt.geom.Rectangle2D
 <ul>
-<li type="circle">java.awt.Rectangle (implements java.io.Serializable, java.awt.Shape)
+<li class="circle">java.awt.Rectangle (implements java.io.Serializable, java.awt.Shape)
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransform</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransform</span></a></li>
 </ul>
 </li>
 </ul>
 </li>
 </ul>
 </li>
-<li type="circle">java.lang.Throwable (implements java.io.Serializable)
+<li class="circle">java.lang.Throwable (implements java.io.Serializable)
 <ul>
-<li type="circle">java.lang.Exception
+<li class="circle">java.lang.Exception
 <ul>
-<li type="circle">java.io.IOException
+<li class="circle">java.io.IOException
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJException</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJException</span></a></li>
 </ul>
 </li>
 </ul>
 </li>
 </ul>
 </li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJ</span></a></li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJCompressor</span></a> (implements java.io.Closeable)</li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJDecompressor</span></a> (implements java.io.Closeable)
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJ</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCompressor</span></a> (implements java.io.Closeable)</li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJDecompressor</span></a> (implements java.io.Closeable)
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJTransformer</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJTransformer</span></a></li>
 </ul>
 </li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">TJScalingFactor</span></a></li>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">YUVImage</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJScalingFactor</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/YUVImage.html" title="class in org.libjpegturbo.turbojpeg"><span class="typeNameLink">YUVImage</span></a></li>
 </ul>
 </li>
 </ul>
+</section>
+<section>
 <h2 title="Interface Hierarchy">Interface Hierarchy</h2>
 <ul>
-<li type="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="strong">TJCustomFilter</span></a></li>
+<li class="circle">org.libjpegturbo.turbojpeg.<a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><span class="typeNameLink">TJCustomFilter</span></a></li>
 </ul>
+</section>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
-<li><a href="org/libjpegturbo/turbojpeg/package-summary.html">Package</a></li>
+<li>Package</li>
 <li>Class</li>
 <li class="navBarCell1Rev">Tree</li>
 <li><a href="deprecated-list.html">Deprecated</a></li>
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?overview-tree.html" target="_top">Frames</a></li>
-<li><a href="overview-tree.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
diff --git a/java/doc/package-search-index.js b/java/doc/package-search-index.js
new file mode 100644 (file)
index 0000000..7f0700b
--- /dev/null
@@ -0,0 +1 @@
+packageSearchIndex = [{"l":"All Packages","url":"allpackages-index.html"},{"l":"org.libjpegturbo.turbojpeg"}]
\ No newline at end of file
diff --git a/java/doc/package-search-index.zip b/java/doc/package-search-index.zip
new file mode 100644 (file)
index 0000000..b55d555
Binary files /dev/null and b/java/doc/package-search-index.zip differ
diff --git a/java/doc/resources/background.gif b/java/doc/resources/background.gif
deleted file mode 100644 (file)
index f471940..0000000
Binary files a/java/doc/resources/background.gif and /dev/null differ
diff --git a/java/doc/resources/glass.png b/java/doc/resources/glass.png
new file mode 100644 (file)
index 0000000..a7f591f
Binary files /dev/null and b/java/doc/resources/glass.png differ
diff --git a/java/doc/resources/tab.gif b/java/doc/resources/tab.gif
deleted file mode 100644 (file)
index 1a73a83..0000000
Binary files a/java/doc/resources/tab.gif and /dev/null differ
diff --git a/java/doc/resources/titlebar.gif b/java/doc/resources/titlebar.gif
deleted file mode 100644 (file)
index 17443b3..0000000
Binary files a/java/doc/resources/titlebar.gif and /dev/null differ
diff --git a/java/doc/resources/titlebar_end.gif b/java/doc/resources/titlebar_end.gif
deleted file mode 100644 (file)
index 3ad78d4..0000000
Binary files a/java/doc/resources/titlebar_end.gif and /dev/null differ
diff --git a/java/doc/resources/x.png b/java/doc/resources/x.png
new file mode 100644 (file)
index 0000000..30548a7
Binary files /dev/null and b/java/doc/resources/x.png differ
index b346356..7dc93c4 100644 (file)
@@ -1,9 +1,124 @@
-function show(type)
-{
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+var moduleSearchIndex;
+var packageSearchIndex;
+var typeSearchIndex;
+var memberSearchIndex;
+var tagSearchIndex;
+function loadScripts(doc, tag) {
+    createElem(doc, tag, 'jquery/jszip/dist/jszip.js');
+    createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils.js');
+    if (window.navigator.userAgent.indexOf('MSIE ') > 0 || window.navigator.userAgent.indexOf('Trident/') > 0 ||
+            window.navigator.userAgent.indexOf('Edge/') > 0) {
+        createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils-ie.js');
+    }
+    createElem(doc, tag, 'search.js');
+
+    $.get(pathtoroot + "module-search-index.zip")
+            .done(function() {
+                JSZipUtils.getBinaryContent(pathtoroot + "module-search-index.zip", function(e, data) {
+                    JSZip.loadAsync(data).then(function(zip){
+                        zip.file("module-search-index.json").async("text").then(function(content){
+                            moduleSearchIndex = JSON.parse(content);
+                        });
+                    });
+                });
+            });
+    $.get(pathtoroot + "package-search-index.zip")
+            .done(function() {
+                JSZipUtils.getBinaryContent(pathtoroot + "package-search-index.zip", function(e, data) {
+                    JSZip.loadAsync(data).then(function(zip){
+                        zip.file("package-search-index.json").async("text").then(function(content){
+                            packageSearchIndex = JSON.parse(content);
+                        });
+                    });
+                });
+            });
+    $.get(pathtoroot + "type-search-index.zip")
+            .done(function() {
+                JSZipUtils.getBinaryContent(pathtoroot + "type-search-index.zip", function(e, data) {
+                    JSZip.loadAsync(data).then(function(zip){
+                        zip.file("type-search-index.json").async("text").then(function(content){
+                            typeSearchIndex = JSON.parse(content);
+                        });
+                    });
+                });
+            });
+    $.get(pathtoroot + "member-search-index.zip")
+            .done(function() {
+                JSZipUtils.getBinaryContent(pathtoroot + "member-search-index.zip", function(e, data) {
+                    JSZip.loadAsync(data).then(function(zip){
+                        zip.file("member-search-index.json").async("text").then(function(content){
+                            memberSearchIndex = JSON.parse(content);
+                        });
+                    });
+                });
+            });
+    $.get(pathtoroot + "tag-search-index.zip")
+            .done(function() {
+                JSZipUtils.getBinaryContent(pathtoroot + "tag-search-index.zip", function(e, data) {
+                    JSZip.loadAsync(data).then(function(zip){
+                        zip.file("tag-search-index.json").async("text").then(function(content){
+                            tagSearchIndex = JSON.parse(content);
+                        });
+                    });
+                });
+            });
+    if (!moduleSearchIndex) {
+        createElem(doc, tag, 'module-search-index.js');
+    }
+    if (!packageSearchIndex) {
+        createElem(doc, tag, 'package-search-index.js');
+    }
+    if (!typeSearchIndex) {
+        createElem(doc, tag, 'type-search-index.js');
+    }
+    if (!memberSearchIndex) {
+        createElem(doc, tag, 'member-search-index.js');
+    }
+    if (!tagSearchIndex) {
+        createElem(doc, tag, 'tag-search-index.js');
+    }
+    $(window).resize(function() {
+        $('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+    });
+}
+
+function createElem(doc, tag, path) {
+    var script = doc.createElement(tag);
+    var scriptElement = doc.getElementsByTagName(tag)[0];
+    script.src = pathtoroot + path;
+    scriptElement.parentNode.insertBefore(script, scriptElement);
+}
+
+function show(type) {
     count = 0;
-    for (var key in methods) {
+    for (var key in data) {
         var row = document.getElementById(key);
-        if ((methods[key] &  type) != 0) {
+        if ((data[key] &  type) !== 0) {
             row.style.display = '';
             row.className = (count++ % 2) ? rowColor : altColor;
         }
@@ -13,8 +128,7 @@ function show(type)
     updateTabs(type);
 }
 
-function updateTabs(type)
-{
+function updateTabs(type) {
     for (var value in tabs) {
         var sNode = document.getElementById(tabs[value][0]);
         var spanNode = sNode.firstChild;
@@ -28,3 +142,8 @@ function updateTabs(type)
         }
     }
 }
+
+function updateModuleFrame(pFrame, cFrame) {
+    top.packageFrame.location = pFrame;
+    top.classFrame.location = cFrame;
+}
diff --git a/java/doc/search.js b/java/doc/search.js
new file mode 100644 (file)
index 0000000..8492271
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+var noResult = {l: "No results found"};
+var catModules = "Modules";
+var catPackages = "Packages";
+var catTypes = "Types";
+var catMembers = "Members";
+var catSearchTags = "SearchTags";
+var highlight = "<span class=\"resultHighlight\">$&</span>";
+var camelCaseRegexp = "";
+var secondaryMatcher = "";
+function getHighlightedText(item) {
+    var ccMatcher = new RegExp(camelCaseRegexp);
+    var label = item.replace(ccMatcher, highlight);
+    if (label === item) {
+        label = item.replace(secondaryMatcher, highlight);
+    }
+    return label;
+}
+function getURLPrefix(ui) {
+    var urlPrefix="";
+    if (useModuleDirectories) {
+        var slash = "/";
+        if (ui.item.category === catModules) {
+            return ui.item.l + slash;
+        } else if (ui.item.category === catPackages && ui.item.m) {
+            return ui.item.m + slash;
+        } else if ((ui.item.category === catTypes && ui.item.p) || ui.item.category === catMembers) {
+            $.each(packageSearchIndex, function(index, item) {
+                if (item.m && ui.item.p == item.l) {
+                    urlPrefix = item.m + slash;
+                }
+            });
+            return urlPrefix;
+        } else {
+            return urlPrefix;
+        }
+    }
+    return urlPrefix;
+}
+var watermark = 'Search';
+$(function() {
+    $("#search").val('');
+    $("#search").prop("disabled", false);
+    $("#reset").prop("disabled", false);
+    $("#search").val(watermark).addClass('watermark');
+    $("#search").blur(function() {
+        if ($(this).val().length == 0) {
+            $(this).val(watermark).addClass('watermark');
+        }
+    });
+    $("#search").on('click keydown', function() {
+        if ($(this).val() == watermark) {
+            $(this).val('').removeClass('watermark');
+        }
+    });
+    $("#reset").click(function() {
+        $("#search").val('');
+        $("#search").focus();
+    });
+    $("#search").focus();
+    $("#search")[0].setSelectionRange(0, 0);
+});
+$.widget("custom.catcomplete", $.ui.autocomplete, {
+    _create: function() {
+        this._super();
+        this.widget().menu("option", "items", "> :not(.ui-autocomplete-category)");
+    },
+    _renderMenu: function(ul, items) {
+        var rMenu = this,
+                currentCategory = "";
+        rMenu.menu.bindings = $();
+        $.each(items, function(index, item) {
+            var li;
+            if (item.l !== noResult.l && item.category !== currentCategory) {
+                ul.append("<li class=\"ui-autocomplete-category\">" + item.category + "</li>");
+                currentCategory = item.category;
+            }
+            li = rMenu._renderItemData(ul, item);
+            if (item.category) {
+                li.attr("aria-label", item.category + " : " + item.l);
+                li.attr("class", "resultItem");
+            } else {
+                li.attr("aria-label", item.l);
+                li.attr("class", "resultItem");
+            }
+        });
+    },
+    _renderItem: function(ul, item) {
+        var label = "";
+        if (item.category === catModules) {
+            label = getHighlightedText(item.l);
+        } else if (item.category === catPackages) {
+            label = (item.m)
+                    ? getHighlightedText(item.m + "/" + item.l)
+                    : getHighlightedText(item.l);
+        } else if (item.category === catTypes) {
+            label = (item.p)
+                    ? getHighlightedText(item.p + "." + item.l)
+                    : getHighlightedText(item.l);
+        } else if (item.category === catMembers) {
+            label = getHighlightedText(item.p + "." + (item.c + "." + item.l));
+        } else if (item.category === catSearchTags) {
+            label = getHighlightedText(item.l);
+        } else {
+            label = item.l;
+        }
+        var li = $("<li/>").appendTo(ul);
+        var div = $("<div/>").appendTo(li);
+        if (item.category === catSearchTags) {
+            if (item.d) {
+                div.html(label + "<span class=\"searchTagHolderResult\"> (" + item.h + ")</span><br><span class=\"searchTagDescResult\">"
+                                + item.d + "</span><br>");
+            } else {
+                div.html(label + "<span class=\"searchTagHolderResult\"> (" + item.h + ")</span>");
+            }
+        } else {
+            div.html(label);
+        }
+        return li;
+    }
+});
+$(function() {
+    $("#search").catcomplete({
+        minLength: 1,
+        delay: 100,
+        source: function(request, response) {
+            var result = new Array();
+            var presult = new Array();
+            var tresult = new Array();
+            var mresult = new Array();
+            var tgresult = new Array();
+            var secondaryresult = new Array();
+            var displayCount = 0;
+            var exactMatcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(request.term) + "$", "i");
+            camelCaseRegexp = ($.ui.autocomplete.escapeRegex(request.term)).split(/(?=[A-Z])/).join("([a-z0-9_$]*?)");
+            var camelCaseMatcher = new RegExp("^" + camelCaseRegexp);
+            secondaryMatcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
+
+            // Return the nested innermost name from the specified object
+            function nestedName(e) {
+                return e.l.substring(e.l.lastIndexOf(".") + 1);
+            }
+
+            function concatResults(a1, a2) {
+                a1 = a1.concat(a2);
+                a2.length = 0;
+                return a1;
+            }
+
+            if (moduleSearchIndex) {
+                var mdleCount = 0;
+                $.each(moduleSearchIndex, function(index, item) {
+                    item.category = catModules;
+                    if (exactMatcher.test(item.l)) {
+                        result.push(item);
+                        mdleCount++;
+                    } else if (camelCaseMatcher.test(item.l)) {
+                        result.push(item);
+                    } else if (secondaryMatcher.test(item.l)) {
+                        secondaryresult.push(item);
+                    }
+                });
+                displayCount = mdleCount;
+                result = concatResults(result, secondaryresult);
+            }
+            if (packageSearchIndex) {
+                var pCount = 0;
+                var pkg = "";
+                $.each(packageSearchIndex, function(index, item) {
+                    item.category = catPackages;
+                    pkg = (item.m)
+                            ? (item.m + "/" + item.l)
+                            : item.l;
+                    if (exactMatcher.test(item.l)) {
+                        presult.push(item);
+                        pCount++;
+                    } else if (camelCaseMatcher.test(pkg)) {
+                        presult.push(item);
+                    } else if (secondaryMatcher.test(pkg)) {
+                        secondaryresult.push(item);
+                    }
+                });
+                result = result.concat(concatResults(presult, secondaryresult));
+                displayCount = (pCount > displayCount) ? pCount : displayCount;
+            }
+            if (typeSearchIndex) {
+                var tCount = 0;
+                $.each(typeSearchIndex, function(index, item) {
+                    item.category = catTypes;
+                    var s = nestedName(item);
+                    if (exactMatcher.test(s)) {
+                        tresult.push(item);
+                        tCount++;
+                    } else if (camelCaseMatcher.test(s)) {
+                        tresult.push(item);
+                    } else if (secondaryMatcher.test(item.p + "." + item.l)) {
+                        secondaryresult.push(item);
+                    }
+                });
+                result = result.concat(concatResults(tresult, secondaryresult));
+                displayCount = (tCount > displayCount) ? tCount : displayCount;
+            }
+            if (memberSearchIndex) {
+                var mCount = 0;
+                $.each(memberSearchIndex, function(index, item) {
+                    item.category = catMembers;
+                    var s = nestedName(item);
+                    if (exactMatcher.test(s)) {
+                        mresult.push(item);
+                        mCount++;
+                    } else if (camelCaseMatcher.test(s)) {
+                        mresult.push(item);
+                    } else if (secondaryMatcher.test(item.c + "." + item.l)) {
+                        secondaryresult.push(item);
+                    }
+                });
+                result = result.concat(concatResults(mresult, secondaryresult));
+                displayCount = (mCount > displayCount) ? mCount : displayCount;
+            }
+            if (tagSearchIndex) {
+                var tgCount = 0;
+                $.each(tagSearchIndex, function(index, item) {
+                    item.category = catSearchTags;
+                    if (exactMatcher.test(item.l)) {
+                        tgresult.push(item);
+                        tgCount++;
+                    } else if (secondaryMatcher.test(item.l)) {
+                        secondaryresult.push(item);
+                    }
+                });
+                result = result.concat(concatResults(tgresult, secondaryresult));
+                displayCount = (tgCount > displayCount) ? tgCount : displayCount;
+            }
+            displayCount = (displayCount > 500) ? displayCount : 500;
+            var counter = function() {
+                var count = {Modules: 0, Packages: 0, Types: 0, Members: 0, SearchTags: 0};
+                var f = function(item) {
+                    count[item.category] += 1;
+                    return (count[item.category] <= displayCount);
+                };
+                return f;
+            }();
+            response(result.filter(counter));
+        },
+        response: function(event, ui) {
+            if (!ui.content.length) {
+                ui.content.push(noResult);
+            } else {
+                $("#search").empty();
+            }
+        },
+        autoFocus: true,
+        position: {
+            collision: "flip"
+        },
+        select: function(event, ui) {
+            if (ui.item.l !== noResult.l) {
+                var url = getURLPrefix(ui);
+                if (ui.item.category === catModules) {
+                    if (useModuleDirectories) {
+                        url += "module-summary.html";
+                    } else {
+                        url = ui.item.l + "-summary.html";
+                    }
+                } else if (ui.item.category === catPackages) {
+                    if (ui.item.url) {
+                        url = ui.item.url;
+                    } else {
+                    url += ui.item.l.replace(/\./g, '/') + "/package-summary.html";
+                    }
+                } else if (ui.item.category === catTypes) {
+                    if (ui.item.url) {
+                        url = ui.item.url;
+                    } else if (ui.item.p === "<Unnamed>") {
+                        url += ui.item.l + ".html";
+                    } else {
+                        url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.l + ".html";
+                    }
+                } else if (ui.item.category === catMembers) {
+                    if (ui.item.p === "<Unnamed>") {
+                        url += ui.item.c + ".html" + "#";
+                    } else {
+                        url += ui.item.p.replace(/\./g, '/') + "/" + ui.item.c + ".html" + "#";
+                    }
+                    if (ui.item.url) {
+                        url += ui.item.url;
+                    } else {
+                        url += ui.item.l;
+                    }
+                } else if (ui.item.category === catSearchTags) {
+                    url += ui.item.u;
+                }
+                if (top !== window) {
+                    parent.classFrame.location = pathtoroot + url;
+                } else {
+                    window.location.href = pathtoroot + url;
+                }
+                $("#search").focus();
+            }
+        }
+    });
+});
index 45bbc86..33cde53 100644 (file)
@@ -1,9 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!DOCTYPE HTML>
 <!-- NewPage -->
 <html lang="en">
 <head>
+<!-- Generated by javadoc -->
 <title>Serialized Form</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery/jquery-ui.min.css" title="Style">
+<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
+<script type="text/javascript" src="script.js"></script>
+<script type="text/javascript" src="jquery/jszip/dist/jszip.min.js"></script>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils.min.js"></script>
+<!--[if IE]>
+<script type="text/javascript" src="jquery/jszip-utils/dist/jszip-utils-ie.min.js"></script>
+<![endif]-->
+<script type="text/javascript" src="jquery/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
 </head>
 <body>
 <script type="text/javascript"><!--
     catch(err) {
     }
 //-->
-</script>
+var pathtoroot = "./";
+var useModuleDirectories = true;
+loadScripts(document, 'script');</script>
 <noscript>
 <div>JavaScript is disabled on your browser.</div>
 </noscript>
+<header role="banner">
+<nav role="navigation">
+<div class="fixedNav">
 <!-- ========= START OF TOP NAVBAR ======= -->
-<div class="topNav"><a name="navbar_top">
+<div class="topNav"><a id="navbar.top">
 <!--   -->
-</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.top.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?serialized-form.html" target="_top">Frames</a></li>
-<li><a href="serialized-form.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_top">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
+</ul>
+<ul class="navListSearch">
+<li><label for="search">SEARCH:</label>
+<input type="text" id="search" value="search" disabled="disabled">
+<input type="reset" id="reset" value="reset" disabled="disabled">
+</li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_top">
+<a id="skip.navbar.top">
 <!--   -->
 </a></div>
 <!-- ========= END OF TOP NAVBAR ========= -->
+</div>
+<div class="navPadding">&nbsp;</div>
+<script type="text/javascript"><!--
+$('.navPadding').css('padding-top', $('.fixedNav').css("height"));
+//-->
+</script>
+</nav>
+</header>
+<main role="main">
 <div class="header">
 <h1 title="Serialized Form" class="title">Serialized Form</h1>
 </div>
 <div class="serializedFormContainer">
 <ul class="blockList">
 <li class="blockList">
+<section>
 <h2 title="Package">Package&nbsp;org.libjpegturbo.turbojpeg</h2>
 <ul class="blockList">
-<li class="blockList"><a name="org.libjpegturbo.turbojpeg.TJException">
+<li class="blockList"><a id="org.libjpegturbo.turbojpeg.TJException">
 <!--   -->
 </a>
 <h3>Class <a href="org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">org.libjpegturbo.turbojpeg.TJException</a> extends java.io.IOException implements Serializable</h3>
 <dd>1L</dd>
 </dl>
 <ul class="blockList">
-<li class="blockList"><a name="serializedForm">
-<!--   -->
-</a>
+<li class="blockList">
 <h3>Serialized Fields</h3>
 <ul class="blockList">
 <li class="blockListLast">
 </li>
 </ul>
 </li>
-<li class="blockList"><a name="org.libjpegturbo.turbojpeg.TJTransform">
+<li class="blockList"><a id="org.libjpegturbo.turbojpeg.TJTransform">
 <!--   -->
 </a>
 <h3>Class <a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">org.libjpegturbo.turbojpeg.TJTransform</a> extends java.awt.Rectangle implements Serializable</h3>
 <dd>-127367705761430371L</dd>
 </dl>
 <ul class="blockList">
-<li class="blockList"><a name="serializedForm">
-<!--   -->
-</a>
+<li class="blockList">
 <h3>Serialized Fields</h3>
 <ul class="blockList">
 <li class="blockList">
+<h4>cf</h4>
+<pre><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a> cf</pre>
+<div class="block">Custom filter instance</div>
+</li>
+<li class="blockList">
 <h4>op</h4>
 <pre>int op</pre>
-<div class="block">Transform operation (one of <code>OP_*</code>)</div>
+<div class="block">Transform operation (one of <a href="org/libjpegturbo/turbojpeg/TJTransform.html#OP_NONE"><code>OP_*</code></a>)</div>
 </li>
-<li class="blockList">
+<li class="blockListLast">
 <h4>options</h4>
 <pre>int options</pre>
-<div class="block">Transform options (bitwise OR of one or more of <code>OPT_*</code>)</div>
-</li>
-<li class="blockListLast">
-<h4>cf</h4>
-<pre><a href="org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg">TJCustomFilter</a> cf</pre>
-<div class="block">Custom filter instance</div>
+<div class="block">Transform options (bitwise OR of one or more of
+ <a href="org/libjpegturbo/turbojpeg/TJTransform.html#OPT_PERFECT"><code>OPT_*</code></a>)</div>
 </li>
 </ul>
 </li>
 </ul>
 </li>
 </ul>
+</section>
 </li>
 </ul>
 </div>
+</main>
+<footer role="contentinfo">
+<nav role="navigation">
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
-<div class="bottomNav"><a name="navbar_bottom">
+<div class="bottomNav"><a id="navbar.bottom">
 <!--   -->
-</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+</a>
+<div class="skipNav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
+<a id="navbar.bottom.firstrow">
 <!--   -->
 </a>
 <ul class="navList" title="Navigation">
 </ul>
 </div>
 <div class="subNav">
-<ul class="navList">
-<li>Prev</li>
-<li>Next</li>
-</ul>
-<ul class="navList">
-<li><a href="index.html?serialized-form.html" target="_top">Frames</a></li>
-<li><a href="serialized-form.html" target="_top">No Frames</a></li>
-</ul>
 <ul class="navList" id="allclasses_navbar_bottom">
-<li><a href="allclasses-noframe.html">All Classes</a></li>
+<li><a href="allclasses.html">All&nbsp;Classes</a></li>
 </ul>
 <div>
 <script type="text/javascript"><!--
   }
   //-->
 </script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
 </div>
-<a name="skip-navbar_bottom">
+<a id="skip.navbar.bottom">
 <!--   -->
 </a></div>
 <!-- ======== END OF BOTTOM NAVBAR ======= -->
+</nav>
+</footer>
 </body>
 </html>
index 0aeaa97..de945ed 100644 (file)
-/* Javadoc style sheet */
+/* 
+ * Javadoc style sheet
+ */
+
+@import url('resources/fonts/dejavu.css');
+
 /*
-Overall document style
-*/
+ * Styles for individual HTML elements.
+ *
+ * These are styles that are specific to individual HTML elements. Changing them affects the style of a particular
+ * HTML element throughout the page.
+ */
+
 body {
     background-color:#ffffff;
     color:#353833;
-    font-family:Arial, Helvetica, sans-serif;
-    font-size:76%;
+    font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
+    font-size:14px;
     margin:0;
+    padding:0;
+    height:100%;
+    width:100%;
+}
+iframe {
+    margin:0;
+    padding:0;
+    height:100%;
+    width:100%;
+    overflow-y:scroll;
+    border:none;
 }
 a:link, a:visited {
     text-decoration:none;
-    color:#4c6b87;
+    color:#4A6782;
 }
-a:hover, a:focus {
+a[href]:hover, a[href]:focus {
     text-decoration:none;
     color:#bb7a2a;
 }
-a:active {
-    text-decoration:none;
-    color:#4c6b87;
-}
 a[name] {
     color:#353833;
 }
-a[name]:hover {
-    text-decoration:none;
-    color:#353833;
+a[name]:before, a[name]:target, a[id]:before, a[id]:target {
+    content:"";
+    display:inline-block;
+    position:relative;
+    padding-top:129px;
+    margin-top:-129px;
 }
 pre {
-    font-size:1.3em;
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
 }
 h1 {
-    font-size:1.8em;
+    font-size:20px;
 }
 h2 {
-    font-size:1.5em;
+    font-size:18px;
 }
 h3 {
-    font-size:1.4em;
+    font-size:16px;
+    font-style:italic;
 }
 h4 {
-    font-size:1.3em;
+    font-size:13px;
 }
 h5 {
-    font-size:1.2em;
+    font-size:12px;
 }
 h6 {
-    font-size:1.1em;
+    font-size:11px;
 }
 ul {
     list-style-type:disc;
 }
 code, tt {
-    font-size:1.2em;
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+    padding-top:4px;
+    margin-top:8px;
+    line-height:1.4em;
 }
 dt code {
-    font-size:1.2em;
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+    padding-top:4px;
 }
 table tr td dt code {
-    font-size:1.2em;
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
     vertical-align:top;
+    padding-top:4px;
 }
 sup {
-    font-size:.6em;
+    font-size:8px;
 }
+
 /*
-Document title and Copyright styles
-*/
+ * Styles for HTML generated by javadoc.
+ *
+ * These are style classes that are used by the standard doclet to generate HTML documentation.
+ */
+
+/*
+ * Styles for document title and copyright.
+ */
 .clear {
     clear:both;
     height:0px;
@@ -76,9 +112,9 @@ Document title and Copyright styles
 .aboutLanguage {
     float:right;
     padding:0px 21px;
-    font-size:.8em;
+    font-size:11px;
     z-index:200;
-    margin-top:-7px;
+    margin-top:-9px;
 }
 .legalCopy {
     margin-left:.5em;
@@ -92,29 +128,33 @@ Document title and Copyright styles
 }
 .tab {
     background-color:#0066FF;
-    background-image:url(resources/titlebar.gif);
-    background-position:left top;
-    background-repeat:no-repeat;
     color:#ffffff;
     padding:8px;
     width:5em;
     font-weight:bold;
 }
 /*
-Navigation bar styles
-*/
+ * Styles for navigation bar.
+ */
 .bar {
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
+    background-color:#4D7A97;
     color:#FFFFFF;
     padding:.8em .5em .4em .8em;
     height:auto;/*height:1.8em;*/
-    font-size:1em;
+    font-size:11px;
     margin:0;
 }
+.navPadding {
+    padding-top: 107px;
+}
+.fixedNav {
+    position:fixed;
+    width:100%;
+    z-index:999;
+    background-color:#ffffff;
+}
 .topNav {
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
+    background-color:#4D7A97;
     color:#FFFFFF;
     float:left;
     padding:0;
@@ -123,11 +163,11 @@ Navigation bar styles
     height:2.8em;
     padding-top:10px;
     overflow:hidden;
+    font-size:12px; 
 }
 .bottomNav {
     margin-top:10px;
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
+    background-color:#4D7A97;
     color:#FFFFFF;
     float:left;
     padding:0;
@@ -136,18 +176,20 @@ Navigation bar styles
     height:2.8em;
     padding-top:10px;
     overflow:hidden;
+    font-size:12px;
 }
 .subNav {
     background-color:#dee3e9;
-    border-bottom:1px solid #9eadc0;
     float:left;
     width:100%;
     overflow:hidden;
+    font-size:12px;
 }
 .subNav div {
     clear:left;
     float:left;
     padding:0 0 5px 6px;
+    text-transform:uppercase;
 }
 ul.navList, ul.subNavList {
     float:left;
@@ -157,42 +199,74 @@ ul.navList, ul.subNavList {
 ul.navList li{
     list-style:none;
     float:left;
-    padding:3px 6px;
+    padding: 5px 6px;
+    text-transform:uppercase;
+}
+ul.navListSearch {
+    float:right;
+    margin:0 0 0 0;
+    padding:0;
+}
+ul.navListSearch li {
+    list-style:none;
+    float:right;
+    padding: 5px 6px;
+    text-transform:uppercase;
 }
-ul.subNavList li{
+ul.navListSearch li label {
+    position:relative;
+    right:-16px;
+}
+ul.subNavList li {
     list-style:none;
     float:left;
-    font-size:90%;
 }
 .topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
     color:#FFFFFF;
     text-decoration:none;
+    text-transform:uppercase;
 }
 .topNav a:hover, .bottomNav a:hover {
     text-decoration:none;
     color:#bb7a2a;
+    text-transform:uppercase;
 }
 .navBarCell1Rev {
-    background-image:url(resources/tab.gif);
-    background-color:#a88834;
-    color:#FFFFFF;
+    background-color:#F8981D;
+    color:#253441;
     margin: auto 5px;
-    border:1px solid #c9aa44;
+}
+.skipNav {
+    position:absolute;
+    top:auto;
+    left:-9999px;
+    overflow:hidden;
 }
 /*
-Page header and footer styles
-*/
+ * Styles for page header and footer.
+ */
 .header, .footer {
     clear:both;
     margin:0 20px;
     padding:5px 0 0 0;
 }
-.indexHeader {
-    margin:10px;
+.indexNav {
     position:relative;
+    font-size:12px;
+    background-color:#dee3e9;
 }
-.indexHeader h1 {
-    font-size:1.3em;
+.indexNav ul {
+    margin-top:0;
+    padding:5px;
+}
+.indexNav ul li {
+    display:inline;
+    list-style-type:none;
+    padding-right:10px;
+    text-transform:uppercase;
+}
+.indexNav h1 {
+    font-size:13px;
 }
 .title {
     color:#2c4557;
@@ -202,7 +276,7 @@ Page header and footer styles
     margin:5px 0 0 0;
 }
 .header ul {
-    margin:0 0 25px 0;
+    margin:0 0 15px 0;
     padding:0;
 }
 .footer ul {
@@ -210,24 +284,22 @@ Page header and footer styles
 }
 .header ul li, .footer ul li {
     list-style:none;
-    font-size:1.2em;
+    font-size:13px;
 }
 /*
-Heading styles
-*/
+ * Styles for headings.
+ */
 div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
     background-color:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
+    border:1px solid #d0d9e0;
     margin:0 0 6px -8px;
-    padding:2px 5px;
+    padding:7px 5px;
 }
 ul.blockList ul.blockList ul.blockList li.blockList h3 {
     background-color:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
+    border:1px solid #d0d9e0;
     margin:0 0 6px -8px;
-    padding:2px 5px;
+    padding:7px 5px;
 }
 ul.blockList ul.blockList li.blockList h3 {
     padding:0;
@@ -237,9 +309,10 @@ ul.blockList li.blockList h2 {
     padding:0px 0 20px 0;
 }
 /*
-Page layout container styles
-*/
-.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
+ * Styles for page layout containers.
+ */
+.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer,
+.allClassesContainer, .allPackagesContainer {
     clear:both;
     padding:10px 20px;
     position:relative;
@@ -247,10 +320,10 @@ Page layout container styles
 .indexContainer {
     margin:10px;
     position:relative;
-    font-size:1.0em;
+    font-size:12px;
 }
 .indexContainer h2 {
-    font-size:1.1em;
+    font-size:13px;
     padding:0 0 3px 0;
 }
 .indexContainer ul {
@@ -259,15 +332,18 @@ Page layout container styles
 }
 .indexContainer ul li {
     list-style:none;
+    padding-top:2px;
 }
 .contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
-    font-size:1.1em;
+    font-size:12px;
     font-weight:bold;
     margin:10px 0 0 0;
     color:#4E4E4E;
 }
 .contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
-    margin:10px 0 10px 20px;
+    margin:5px 0 10px 0px;
+    font-size:14px;
+    font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
 }
 .serializedFormContainer dl.nameValue dt {
     margin-left:1px;
@@ -281,8 +357,11 @@ Page layout container styles
     display:inline;
 }
 /*
-List styles
-*/
+ * Styles for lists.
+ */
+li.circle {
+    list-style:circle;
+}
 ul.horizontal li {
     display:inline;
     font-size:0.9em;
@@ -306,25 +385,24 @@ ul.blockList, ul.blockListLast {
 }
 ul.blockList li.blockList, ul.blockListLast li.blockList {
     list-style:none;
-    margin-bottom:25px;
+    margin-bottom:15px;
+    line-height:1.4;
 }
 ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
     padding:0px 20px 5px 10px;
-    border:1px solid #9eadc0;
-    background-color:#f9f9f9;
+    border:1px solid #ededed; 
+    background-color:#f8f8f8;
 }
 ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
     padding:0 0 5px 8px;
     background-color:#ffffff;
-    border:1px solid #9eadc0;
-    border-top:none;
+    border:none;
 }
 ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
     margin-left:0;
     padding-left:0;
     padding-bottom:15px;
     border:none;
-    border-bottom:1px solid #9eadc0;
 }
 ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
     list-style:none;
@@ -336,113 +414,207 @@ table tr td dl, table tr td dl dt, table tr td dl dd {
     margin-bottom:1px;
 }
 /*
-Table styles
-*/
-.contentContainer table, .classUseContainer table, .constantValuesContainer table {
-    border-bottom:1px solid #9eadc0;
-    width:100%;
-}
-.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table {
+ * Styles for tables.
+ */
+.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary,
+.requiresSummary, .packagesSummary, .providesSummary, .usesSummary {
     width:100%;
+    border-spacing:0;
+    border-left:1px solid #EEE; 
+    border-right:1px solid #EEE; 
+    border-bottom:1px solid #EEE; 
 }
-.contentContainer .description table, .contentContainer .details table {
-    border-bottom:none;
-}
-.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{
-    vertical-align:top;
-    padding-right:20px;
-}
-.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast,
-.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast,
-.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne,
-.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne {
-    padding-right:3px;
+.overviewSummary, .memberSummary, .requiresSummary, .packagesSummary, .providesSummary, .usesSummary  {
+    padding:0px;
 }
-.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption {
+.overviewSummary caption, .memberSummary caption, .typeSummary caption,
+.useSummary caption, .constantsSummary caption, .deprecatedSummary caption,
+.requiresSummary caption, .packagesSummary caption, .providesSummary caption, .usesSummary caption {
     position:relative;
     text-align:left;
     background-repeat:no-repeat;
-    color:#FFFFFF;
+    color:#253441;
     font-weight:bold;
     clear:none;
     overflow:hidden;
     padding:0px;
+    padding-top:10px;
+    padding-left:1px;
     margin:0px;
-}
-caption a:link, caption a:hover, caption a:active, caption a:visited {
+    white-space:pre;
+}
+.constantsSummary caption a:link, .constantsSummary caption a:visited,
+.useSummary caption a:link, .useSummary caption a:visited {
+    color:#1f389c;
+}
+.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,
+.deprecatedSummary caption a:link,
+.requiresSummary caption a:link, .packagesSummary caption a:link, .providesSummary caption a:link,
+.usesSummary caption a:link,
+.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,
+.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,
+.requiresSummary caption a:hover, .packagesSummary caption a:hover, .providesSummary caption a:hover,
+.usesSummary caption a:hover,
+.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,
+.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,
+.requiresSummary caption a:active, .packagesSummary caption a:active, .providesSummary caption a:active,
+.usesSummary caption a:active,
+.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,
+.deprecatedSummary caption a:visited,
+.requiresSummary caption a:visited, .packagesSummary caption a:visited, .providesSummary caption a:visited,
+.usesSummary caption a:visited {
     color:#FFFFFF;
 }
-.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span {
+.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,
+.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span,
+.requiresSummary caption span, .packagesSummary caption span, .providesSummary caption span,
+.usesSummary caption span {
     white-space:nowrap;
-    padding-top:8px;
-    padding-left:8px;
-    display:block;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    padding-bottom:7px;
+    display:inline-block;
     float:left;
-    background-image:url(resources/titlebar.gif);
-    height:18px;
+    background-color:#F8981D;
+    border: none;
+    height:16px;
 }
-.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd {
-    width:10px;
-    background-image:url(resources/titlebar_end.gif);
-    background-repeat:no-repeat;
-    background-position:top right;
-    position:relative;
+.memberSummary caption span.activeTableTab span, .packagesSummary caption span.activeTableTab span,
+.overviewSummary caption span.activeTableTab span, .typeSummary caption span.activeTableTab span {
+    white-space:nowrap;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    margin-right:3px;
+    display:inline-block;
     float:left;
+    background-color:#F8981D;
+    height:16px;
 }
-ul.blockList ul.blockList li.blockList table {
-    margin:0 0 12px 0px;
-    width:100%;
+.memberSummary caption span.tableTab span, .packagesSummary caption span.tableTab span,
+.overviewSummary caption span.tableTab span, .typeSummary caption span.tableTab span {
+    white-space:nowrap;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    margin-right:3px;
+    display:inline-block;
+    float:left;
+    background-color:#4D7A97;
+    height:16px;
+}
+.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab,
+.packagesSummary caption span.tableTab, .packagesSummary caption span.activeTableTab,
+.overviewSummary caption span.tableTab, .overviewSummary caption span.activeTableTab,
+.typeSummary caption span.tableTab, .typeSummary caption span.activeTableTab {
+    padding-top:0px;
+    padding-left:0px;
+    padding-right:0px;
+    background-image:none;
+    float:none;
+    display:inline;
 }
-.tableSubHeadingColor {
-    background-color: #EEEEFF;
+.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,
+.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd,
+.requiresSummary .tabEnd, .packagesSummary .tabEnd, .providesSummary .tabEnd, .usesSummary .tabEnd {
+    display:none;
+    width:5px;
+    position:relative;
+    float:left;
+    background-color:#F8981D;
+}
+.memberSummary .activeTableTab .tabEnd, .packagesSummary .activeTableTab .tabEnd,
+.overviewSummary .activeTableTab .tabEnd, .typeSummary .activeTableTab .tabEnd {
+    display:none;
+    width:5px;
+    margin-right:3px;
+    position:relative; 
+    float:left;
+    background-color:#F8981D;
 }
-.altColor {
-    background-color:#eeeeef;
+.memberSummary .tableTab .tabEnd, .packagesSummary .tableTab .tabEnd,
+.overviewSummary .tableTab .tabEnd, .typeSummary .tableTab .tabEnd {
+    display:none;
+    width:5px;
+    margin-right:3px;
+    position:relative;
+    background-color:#4D7A97;
+    float:left;
 }
-.rowColor {
-    background-color:#ffffff;
+.rowColor th, .altColor th {
+    font-weight:normal;
 }
-.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td {
+.overviewSummary td, .memberSummary td, .typeSummary td,
+.useSummary td, .constantsSummary td, .deprecatedSummary td,
+.requiresSummary td, .packagesSummary td, .providesSummary td, .usesSummary td {
     text-align:left;
-    padding:3px 3px 3px 7px;
+    padding:0px 0px 12px 10px;
+}
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th,
+.constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td,
+.constantsSummary td {
+    vertical-align:top;
+    padding-right:0px;
+    padding-top:8px;
+    padding-bottom:3px;
 }
-th.colFirst, th.colLast, th.colOne, .constantValuesContainer th {
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th,
+.packagesSummary th {
     background:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
     text-align:left;
-    padding:3px 3px 3px 7px;
-}
-td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
-    font-weight:bold;
+    padding:8px 3px 3px 7px;
 }
 td.colFirst, th.colFirst {
-    border-left:1px solid #9eadc0;
-    white-space:nowrap;
-}
-td.colLast, th.colLast {
-    border-right:1px solid #9eadc0;
+    font-size:13px;
+}
+td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast {
+    font-size:13px;
+}
+.constantsSummary th, .packagesSummary th {
+    font-size:13px;
+}
+.providesSummary th.colFirst, .providesSummary th.colLast, .providesSummary td.colFirst,
+.providesSummary td.colLast {
+    white-space:normal;
+    font-size:13px;
+}
+.overviewSummary td.colFirst, .overviewSummary th.colFirst,
+.requiresSummary td.colFirst, .requiresSummary th.colFirst,
+.packagesSummary td.colFirst, .packagesSummary td.colSecond, .packagesSummary th.colFirst, .packagesSummary th,
+.usesSummary td.colFirst, .usesSummary th.colFirst,
+.providesSummary td.colFirst, .providesSummary th.colFirst,
+.memberSummary td.colFirst, .memberSummary th.colFirst,
+.memberSummary td.colSecond, .memberSummary th.colSecond, .memberSummary th.colConstructorName,
+.typeSummary td.colFirst, .typeSummary th.colFirst {
+    vertical-align:top;
 }
-td.colOne, th.colOne {
-    border-right:1px solid #9eadc0;
-    border-left:1px solid #9eadc0;
+.packagesSummary th.colLast, .packagesSummary td.colLast {
+    white-space:normal;
+}
+td.colFirst a:link, td.colFirst a:visited,
+td.colSecond a:link, td.colSecond a:visited,
+th.colFirst a:link, th.colFirst a:visited,
+th.colSecond a:link, th.colSecond a:visited,
+th.colConstructorName a:link, th.colConstructorName a:visited,
+th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited, 
+.constantValuesContainer td a:link, .constantValuesContainer td a:visited, 
+.allClassesContainer td a:link, .allClassesContainer td a:visited, 
+.allPackagesContainer td a:link, .allPackagesContainer td a:visited {
+    font-weight:bold;
 }
-table.overviewSummary  {
-    padding:0px;
-    margin-left:0px;
+.tableSubHeadingColor {
+    background-color:#EEEEFF;
 }
-table.overviewSummary td.colFirst, table.overviewSummary th.colFirst,
-table.overviewSummary td.colOne, table.overviewSummary th.colOne {
-    width:25%;
-    vertical-align:middle;
+.altColor, .altColor th {
+    background-color:#FFFFFF;
 }
-table.packageSummary td.colFirst, table.overviewSummary th.colFirst {
-    width:25%;
-    vertical-align:middle;
+.rowColor, .rowColor th {
+    background-color:#EEEEEF;
 }
 /*
-Content styles
-*/
+ * Styles for contents.
+ */
 .description pre {
     margin-top:0;
 }
@@ -453,9 +625,22 @@ Content styles
 .docSummary {
     padding:0;
 }
+ul.blockList ul.blockList ul.blockList li.blockList h3 {
+    font-style:normal;
+}
+div.block {
+    font-size:14px;
+    font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+}
+td.colLast div {
+    padding-top:0px;
+}
+td.colLast a {
+    padding-bottom:3px;
+}
 /*
-Formatting effect styles
-*/
+ * Styles for formatting effect.
+ */
 .sourceLineNo {
     color:green;
     padding:0 30px 0 0;
@@ -463,12 +648,263 @@ Formatting effect styles
 h1.hidden {
     visibility:hidden;
     overflow:hidden;
-    font-size:.9em;
+    font-size:10px;
 }
 .block {
     display:block;
-    margin:3px 0 0 0;
+    margin:3px 10px 2px 0px;
+    color:#474747;
+}
+.deprecatedLabel, .descfrmTypeLabel, .implementationLabel, .memberNameLabel, .memberNameLink,
+.moduleLabelInPackage, .moduleLabelInType, .overrideSpecifyLabel, .packageLabelInType,
+.packageHierarchyLabel, .paramLabel, .returnLabel, .seeLabel, .simpleTagLabel,
+.throwsLabel, .typeNameLabel, .typeNameLink, .searchTagLink {
+    font-weight:bold;
+}
+.deprecationComment, .emphasizedPhrase, .interfaceName {
+    font-style:italic;
+}
+.deprecationBlock {
+    font-size:14px;
+    font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+    border-style:solid;
+    border-width:thin;
+    border-radius:10px;
+    padding:10px;
+    margin-bottom:10px;
+    margin-right:10px;
+    display:inline-block;
+}
+div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
+div.block div.block span.interfaceName {
+    font-style:normal;
+}
+div.contentContainer ul.blockList li.blockList h2 {
+    padding-bottom:0px;
+}
+/*
+ * Styles for IFRAME.
+ */
+.mainContainer {
+    margin:0 auto; 
+    padding:0; 
+    height:100%; 
+    width:100%; 
+    position:fixed; 
+    top:0; 
+    left:0;
+}
+.leftContainer {
+    height:100%;
+    position:fixed;
+    width:320px;
+}
+.leftTop {
+    position:relative;
+    float:left;
+    width:315px;
+    top:0;
+    left:0;
+    height:30%;
+    border-right:6px solid #ccc;
+    border-bottom:6px solid #ccc;
+}
+.leftBottom {
+    position:relative;
+    float:left;
+    width:315px;
+    bottom:0;
+    left:0;
+    height:70%;
+    border-right:6px solid #ccc;
+    border-top:1px solid #000;
+}
+.rightContainer {
+    position:absolute;
+    left:320px;
+    top:0;
+    bottom:0;
+    height:100%;
+    right:0;
+    border-left:1px solid #000;
+}
+.rightIframe {
+    margin:0;
+    padding:0;
+    height:100%;
+    right:30px;
+    width:100%;
+    overflow:visible;
+    margin-bottom:30px;
+}
+/*
+ * Styles specific to HTML5 elements.
+ */
+main, nav, header, footer, section {
+    display:block;
+}
+/*
+ * Styles for javadoc search.
+ */
+.ui-autocomplete-category {
+    font-weight:bold;
+    font-size:15px;
+    padding:7px 0 7px 3px;
+    background-color:#4D7A97;
+    color:#FFFFFF;
+}
+.resultItem {
+    font-size:13px;
 }
-.strong {
+.ui-autocomplete {
+    max-height:85%;
+    max-width:65%;
+    overflow-y:scroll;
+    overflow-x:scroll;
+    white-space:nowrap;
+    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
+}
+ul.ui-autocomplete {
+    position:fixed;
+    z-index:999999;
+    background-color: #FFFFFF;
+}
+ul.ui-autocomplete  li {
+    float:left;
+    clear:both;
+    width:100%;
+}
+.resultHighlight {
     font-weight:bold;
 }
+.ui-autocomplete .result-item {
+    font-size: inherit;
+}
+#search {
+    background-image:url('resources/glass.png');
+    background-size:13px;
+    background-repeat:no-repeat;
+    background-position:2px 3px;
+    padding-left:20px;
+    position:relative;
+    right:-18px;
+}
+#reset {
+    background-color: rgb(255,255,255);
+    background-image:url('resources/x.png');
+    background-position:center;
+    background-repeat:no-repeat;
+    background-size:12px;
+    border:0 none;
+    width:16px;
+    height:17px;
+    position:relative;
+    left:-4px;
+    top:-4px;
+    font-size:0px;
+}
+.watermark {
+    color:#545454;
+}
+.searchTagDescResult {
+    font-style:italic;
+    font-size:11px;
+}
+.searchTagHolderResult {
+    font-style:italic;
+    font-size:12px;
+}
+.searchTagResult:before, .searchTagResult:target {
+    color:red;
+}
+.moduleGraph span {
+    display:none;
+    position:absolute;
+}
+.moduleGraph:hover span {
+    display:block;
+    margin: -100px 0 0 100px;
+    z-index: 1;
+}
+.methodSignature {
+    white-space:normal;
+}
+
+/*
+ * Styles for user-provided tables.
+ *
+ * borderless:
+ *      No borders, vertical margins, styled caption.
+ *      This style is provided for use with existing doc comments.
+ *      In general, borderless tables should not be used for layout purposes.
+ *
+ * plain:
+ *      Plain borders around table and cells, vertical margins, styled caption.
+ *      Best for small tables or for complex tables for tables with cells that span
+ *      rows and columns, when the "striped" style does not work well.
+ *
+ * striped:
+ *      Borders around the table and vertical borders between cells, striped rows,
+ *      vertical margins, styled caption.
+ *      Best for tables that have a header row, and a body containing a series of simple rows.
+ */
+
+table.borderless,
+table.plain,
+table.striped {
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+table.borderless > caption,
+table.plain > caption,
+table.striped > caption {
+    font-weight: bold;
+    font-size: smaller;
+}
+table.borderless th, table.borderless td,
+table.plain th, table.plain td,
+table.striped th, table.striped td {
+    padding: 2px 5px;
+}
+table.borderless,
+table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th,
+table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td {
+    border: none;
+}
+table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr {
+    background-color: transparent;
+}
+table.plain {
+    border-collapse: collapse;
+    border: 1px solid black;
+}
+table.plain > thead > tr, table.plain > tbody tr, table.plain > tr {
+    background-color: transparent;
+}
+table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr > th,
+table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td {
+    border: 1px solid black;
+}
+table.striped {
+    border-collapse: collapse;
+    border: 1px solid black;
+}
+table.striped > thead {
+    background-color: #E3E3E3;
+}
+table.striped > thead > tr > th, table.striped > thead > tr > td {
+    border: 1px solid black;
+}
+table.striped > tbody > tr:nth-child(even) {
+    background-color: #EEE
+}
+table.striped > tbody > tr:nth-child(odd) {
+    background-color: #FFF
+}
+table.striped > tbody > tr > th, table.striped > tbody > tr > td {
+    border-left: 1px solid black;
+    border-right: 1px solid black;
+}
+table.striped > tbody > tr > th {
+    font-weight: normal;
+}
diff --git a/java/doc/type-search-index.js b/java/doc/type-search-index.js
new file mode 100644 (file)
index 0000000..d4bc564
--- /dev/null
@@ -0,0 +1 @@
+typeSearchIndex = [{"l":"All Classes","url":"allclasses-index.html"},{"p":"org.libjpegturbo.turbojpeg","l":"TJ"},{"p":"org.libjpegturbo.turbojpeg","l":"TJCompressor"},{"p":"org.libjpegturbo.turbojpeg","l":"TJCustomFilter"},{"p":"org.libjpegturbo.turbojpeg","l":"TJDecompressor"},{"p":"org.libjpegturbo.turbojpeg","l":"TJException"},{"p":"org.libjpegturbo.turbojpeg","l":"TJScalingFactor"},{"p":"org.libjpegturbo.turbojpeg","l":"TJTransform"},{"p":"org.libjpegturbo.turbojpeg","l":"TJTransformer"},{"p":"org.libjpegturbo.turbojpeg","l":"YUVImage"}]
\ No newline at end of file
diff --git a/java/doc/type-search-index.zip b/java/doc/type-search-index.zip
new file mode 100644 (file)
index 0000000..3f8aad1
Binary files /dev/null and b/java/doc/type-search-index.zip differ
index d791e00..65f7ad3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2013, 2017-2018, 2020-2021 D. R. Commander.
+ * Copyright (C)2011-2013, 2017-2018, 2020-2023 D. R. Commander.
  *                                              All Rights Reserved.
  * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
  *
@@ -30,6 +30,8 @@
 
 package org.libjpegturbo.turbojpeg;
 
+import java.awt.Rectangle;
+
 /**
  * TurboJPEG utility class (cannot be instantiated)
  */
@@ -40,7 +42,7 @@ public final class TJ {
   /**
    * The number of chrominance subsampling options
    */
-  public static final int NUMSAMP   = 6;
+  public static final int NUMSAMP   = 7;
   /**
    * 4:4:4 chrominance subsampling (no chrominance subsampling).  The JPEG
    * or YUV image will contain one chrominance component for every pixel in the
@@ -78,14 +80,36 @@ public final class TJ {
    * in libjpeg-turbo.
    */
   public static final int SAMP_411  = 5;
-
+  /**
+   * 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.
+   * JPEG images compressed with 4:4: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:4:1 is better able to reproduce sharp
+   * vertical features.  Note that 4:4:1 subsampling is not fully accelerated
+   * in libjpeg-turbo.
+   */
+  public static final int SAMP_441  = 6;
+  /**
+   * 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
+   * <ul>
+   * <li> decompressed into planar YUV images,
+   * <li> losslessly transformed if {@link TJTransform#OPT_CROP} is specified,
+   * or
+   * <li> partially decompressed using a cropping region.
+   * </ul>
+   */
+  public static final int SAMP_UNKNOWN = -1;
 
   /**
    * Returns the MCU block width for the given level of chrominance
    * subsampling.
    *
    * @param subsamp the level of chrominance subsampling (one of
-   * <code>SAMP_*</code>)
+   * {@link #SAMP_444 SAMP_*})
    *
    * @return the MCU block width for the given level of chrominance
    * subsampling.
@@ -96,7 +120,7 @@ public final class TJ {
   }
 
   private static final int[] MCU_WIDTH = {
-    8, 16, 16, 8, 8, 32
+    8, 16, 16, 8, 8, 32, 8
   };
 
 
@@ -105,7 +129,7 @@ public final class TJ {
    * subsampling.
    *
    * @param subsamp the level of chrominance subsampling (one of
-   * <code>SAMP_*</code>)
+   * {@link #SAMP_444 SAMP_*})
    *
    * @return the MCU block height for the given level of chrominance
    * subsampling.
@@ -116,7 +140,7 @@ public final class TJ {
   }
 
   private static final int[] MCU_HEIGHT = {
-    8, 8, 16, 8, 16, 8
+    8, 8, 16, 8, 16, 8, 32
   };
 
 
@@ -126,71 +150,72 @@ public final class TJ {
   public static final int NUMPF   = 12;
   /**
    * 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.
+   * stored in 3-sample pixels in the order R, G, B from lowest to highest
+   * memory address within each pixel.
    */
   public static final int PF_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.
+   * stored in 3-sample pixels in the order B, G, R from lowest to highest
+   * memory address within each pixel.
    */
   public static final int PF_BGR  = 1;
   /**
    * 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.
+   * 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 and undefined when decompressing.
    */
   public static final int PF_RGBX = 2;
   /**
    * 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.
+   * 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 and undefined when decompressing.
    */
   public static final int PF_BGRX = 3;
   /**
    * 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.
+   * 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 and undefined when decompressing.
    */
   public static final int PF_XBGR = 4;
   /**
    * 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.
+   * 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 and undefined when decompressing.
    */
   public static final int PF_XRGB = 5;
   /**
-   * Grayscale pixel format.  Each 1-byte pixel represents a luminance
-   * (brightness) level from 0 to 255.
+   * Grayscale pixel format.  Each 1-sample pixel represents a luminance
+   * (brightness) level from 0 to the maximum sample value (255 for 8-bit
+   * samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.)
    */
   public static final int PF_GRAY = 6;
   /**
    * RGBA pixel format.  This is the same as {@link #PF_RGBX}, except that when
-   * decompressing, the X byte is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, the X component is guaranteed to be equal to the maximum
+   * sample value, which can be interpreted as an opaque alpha channel.
    */
   public static final int PF_RGBA = 7;
   /**
    * BGRA pixel format.  This is the same as {@link #PF_BGRX}, except that when
-   * decompressing, the X byte is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, the X component is guaranteed to be equal to the maximum
+   * sample value, which can be interpreted as an opaque alpha channel.
    */
   public static final int PF_BGRA = 8;
   /**
    * ABGR pixel format.  This is the same as {@link #PF_XBGR}, except that when
-   * decompressing, the X byte is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, the X component is guaranteed to be equal to the maximum
+   * sample value, which can be interpreted as an opaque alpha channel.
    */
   public static final int PF_ABGR = 9;
   /**
    * ARGB pixel format.  This is the same as {@link #PF_XRGB}, except that when
-   * decompressing, the X byte is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, the X component is guaranteed to be equal to the maximum
+   * sample value, which can be interpreted as an opaque alpha channel.
    */
   public static final int PF_ARGB = 10;
   /**
@@ -205,18 +230,18 @@ public final class TJ {
    * vice versa, but the mapping is typically not 1:1 or reversible, nor can it
    * be defined with a simple formula.  Thus, such a conversion is out of scope
    * for a codec library.  However, the TurboJPEG API allows for compressing
-   * CMYK pixels into a YCCK JPEG image (see {@link #CS_YCCK}) and
-   * decompressing YCCK JPEG images into CMYK pixels.
+   * packed-pixel CMYK images into YCCK JPEG images (see {@link #CS_YCCK}) and
+   * decompressing YCCK JPEG images into packed-pixel CMYK images.
    */
   public static final int PF_CMYK = 11;
 
 
   /**
-   * Returns the pixel size (in bytes) for the given pixel format.
+   * Returns the pixel size (in samples) for the given pixel format.
    *
-   * @param pixelFormat the pixel format (one of <code>PF_*</code>)
+   * @param pixelFormat the pixel format (one of {@link #PF_RGB PF_*})
    *
-   * @return the pixel size (in bytes) for the given pixel format.
+   * @return the pixel size (in samples) for the given pixel format.
    */
   public static int getPixelSize(int pixelFormat) {
     checkPixelFormat(pixelFormat);
@@ -229,13 +254,13 @@ public final class TJ {
 
 
   /**
-   * For the given pixel format, returns the number of bytes that the red
-   * component is offset from the start of the pixel.  For instance, if a pixel
-   * of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
-   * then the red component will be
+   * For the given pixel format, returns the number of samples that the red
+   * component is offset from the start of the pixel.  For instance, if an
+   * 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
+   * <code>char pixel[]</code>, then the red component will be
    * <code>pixel[TJ.getRedOffset(TJ.PF_BGRX)]</code>.
    *
-   * @param pixelFormat the pixel format (one of <code>PF_*</code>)
+   * @param pixelFormat the pixel format (one of {@link #PF_RGB PF_*})
    *
    * @return the red offset for the given pixel format, or -1 if the pixel
    * format does not have a red component.
@@ -251,13 +276,13 @@ public final class TJ {
 
 
   /**
-   * For the given pixel format, returns the number of bytes that the green
-   * component is offset from the start of the pixel.  For instance, if a pixel
-   * of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
-   * then the green component will be
+   * For the given pixel format, returns the number of samples that the green
+   * component is offset from the start of the pixel.  For instance, if an
+   * 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
+   * <code>char pixel[]</code>, then the green component will be
    * <code>pixel[TJ.getGreenOffset(TJ.PF_BGRX)]</code>.
    *
-   * @param pixelFormat the pixel format (one of <code>PF_*</code>)
+   * @param pixelFormat the pixel format (one of {@link #PF_RGB PF_*})
    *
    * @return the green offset for the given pixel format, or -1 if the pixel
    * format does not have a green component.
@@ -273,13 +298,13 @@ public final class TJ {
 
 
   /**
-   * For the given pixel format, returns the number of bytes that the blue
-   * component is offset from the start of the pixel.  For instance, if a pixel
-   * of format <code>TJ.PF_BGRX</code> is stored in <code>char pixel[]</code>,
-   * then the blue component will be
+   * For the given pixel format, returns the number of samples that the blue
+   * component is offset from the start of the pixel.  For instance, if an
+   * 8-bit-per-sample pixel of format <code>TJ.PF_BGRX</code> is stored in
+   * <code>char pixel[]</code>, then the blue component will be
    * <code>pixel[TJ.getBlueOffset(TJ.PF_BGRX)]</code>.
    *
-   * @param pixelFormat the pixel format (one of <code>PF_*</code>)
+   * @param pixelFormat the pixel format (one of {@link #PF_RGB PF_*})
    *
    * @return the blue offset for the given pixel format, or -1 if the pixel
    * format does not have a blue component.
@@ -295,13 +320,13 @@ public final class TJ {
 
 
   /**
-   * For the given pixel format, returns the number of bytes that the alpha
-   * component is offset from the start of the pixel.  For instance, if a pixel
-   * of format <code>TJ.PF_BGRA</code> is stored in <code>char pixel[]</code>,
-   * then the alpha component will be
+   * For the given pixel format, returns the number of samples that the alpha
+   * component is offset from the start of the pixel.  For instance, if an
+   * 8-bit-per-sample pixel of format <code>TJ.PF_BGRA</code> is stored in
+   * <code>char pixel[]</code>, then the alpha component will be
    * <code>pixel[TJ.getAlphaOffset(TJ.PF_BGRA)]</code>.
    *
-   * @param pixelFormat the pixel format (one of <code>PF_*</code>)
+   * @param pixelFormat the pixel format (one of {@link #PF_RGB PF_*})
    *
    * @return the alpha offset for the given pixel format, or -1 if the pixel
    * format does not have a alpha component.
@@ -324,8 +349,9 @@ public final class TJ {
    * RGB colorspace.  When compressing the JPEG image, the R, G, and B
    * components in the source image are reordered into image planes, but no
    * colorspace conversion or subsampling is performed.  RGB JPEG images can be
-   * decompressed to any of the extended RGB pixel formats or grayscale, but
-   * they cannot be decompressed to YUV images.
+   * compressed from and decompressed to packed-pixel images with any of the
+   * extended RGB or grayscale pixel formats, but they cannot be compressed
+   * from or decompressed to planar YUV images.
    */
   public static final int CS_RGB = 0;
   /**
@@ -339,26 +365,29 @@ public final class TJ {
    * transformation allowed the same signal to drive both black &amp; white and
    * color televisions, but JPEG images use YCbCr primarily because it allows
    * the color data to be optionally subsampled for the purposes of reducing
-   * bandwidth or disk space.  YCbCr is the most common JPEG colorspace, and
-   * YCbCr JPEG images can be compressed from and decompressed to any of the
-   * extended RGB pixel formats or grayscale, or they can be decompressed to
-   * YUV planar images.
+   * 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.
    */
   @SuppressWarnings("checkstyle:ConstantName")
   public static final int CS_YCbCr = 1;
   /**
    * Grayscale colorspace.  The JPEG image retains only the luminance data (Y
    * component), and any color data from the source image is discarded.
-   * Grayscale JPEG images can be compressed from and decompressed to any of
-   * the extended RGB pixel formats or grayscale, or they can be decompressed
-   * to YUV planar images.
+   * Grayscale JPEG images can be compressed from and decompressed to
+   * packed-pixel images with any of the extended RGB or grayscale pixel
+   * formats, or they can be compressed from and decompressed to planar YUV
+   * images.
    */
   public static final int CS_GRAY = 2;
   /**
    * CMYK colorspace.  When compressing the JPEG image, the C, M, Y, and K
    * components in the source image are reordered into image planes, but no
    * colorspace conversion or subsampling is performed.  CMYK JPEG images can
-   * only be decompressed to CMYK pixels.
+   * only be compressed from and decompressed to packed-pixel images with the
+   * CMYK pixel format.
    */
   public static final int CS_CMYK = 3;
   /**
@@ -368,85 +397,419 @@ public final class TJ {
    * reversibly transformed into YCCK, and as with YCbCr, the chrominance
    * components in the YCCK pixels can be subsampled without incurring major
    * perceptual loss.  YCCK JPEG images can only be compressed from and
-   * decompressed to CMYK pixels.
+   * decompressed to packed-pixel images with the CMYK pixel format.
    */
   public static final int CS_YCCK = 4;
 
 
   /**
-   * The uncompressed source/destination image is stored in bottom-up (Windows,
-   * OpenGL) order, not top-down (X11) order.
+   * Error handling behavior
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default]</i> Allow the current
+   * compression/decompression/transform operation to complete unless a fatal
+   * error is encountered.
+   * <li> <code>1</code> Immediately discontinue the current
+   * compression/decompression/transform operation if a warning (non-fatal
+   * error) occurs.
+   * </ul>
    */
-  public static final int FLAG_BOTTOMUP      = 2;
+  public static final int PARAM_STOPONWARNING = 0;
+  /**
+   * Row order in packed-pixel source/destination images
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default]</i> top-down (X11) order
+   * <li> <code>1</code> bottom-up (Windows, OpenGL) order
+   * </ul>
+   */
+  public static final int PARAM_BOTTOMUP = 1;
+  /**
+   * Perceptual quality of lossy JPEG images [compression only]
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>1</code>-<code>100</code> (<code>1</code> = worst quality but
+   * best compression, <code>100</code> = best quality but worst compression)
+   * <i>[no default; must be explicitly specified]</i>
+   * </ul>
+   */
+  public static final int PARAM_QUALITY = 3;
+  /**
+   * Chrominance subsampling level
+   *
+   * <p>The JPEG or YUV image uses (decompression, decoding) or will use (lossy
+   * compression, encoding) the specified level of chrominance subsampling.
+   *
+   * <p>When pixels are converted from RGB to YCbCr (see {@link #CS_YCbCr}) or
+   * from CMYK to YCCK (see {@link #CS_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".
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> One of {@link TJ#SAMP_444 TJ.SAMP_*} <i>[no default; must be
+   * explicitly specified for lossy compression, encoding, and decoding]</i>
+   * </ul>
+   */
+  public static final int PARAM_SUBSAMP = 4;
+  /**
+   * JPEG width (in pixels) [decompression only, read-only]
+   */
+  public static final int PARAM_JPEGWIDTH = 5;
+  /**
+   * JPEG height (in pixels) [decompression only, read-only]
+   */
+  public static final int PARAM_JPEGHEIGHT = 6;
+  /**
+   * JPEG data precision (bits per sample) [decompression only, read-only]
+   *
+   * <p>The JPEG image uses the specified number of bits per sample.
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>8</code>, <code>12</code>, or <code>16</code>
+   * </ul>
+   *
+   * <p>12-bit data precision implies {@link #PARAM_OPTIMIZE} unless
+   * {@link #PARAM_ARITHMETIC} is set.
+   */
+  public static final int PARAM_PRECISION = 7;
+  /**
+   * JPEG colorspace
+   *
+   * <p>The JPEG image uses (decompression) or will use (lossy compression) the
+   * specified colorspace.
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> One of {@link TJ#CS_RGB TJ.CS_*} <i>[default for lossy compression:
+   * automatically selected based on the subsampling level and pixel
+   * format]</i>
+   * </ul>
+   */
+  public static final int PARAM_COLORSPACE = 8;
+  /**
+   * Chrominance upsampling algorithm [lossy decompression only]
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default]</i> Use smooth upsampling when
+   * decompressing a JPEG image that was compressed using chrominance
+   * subsampling.  This creates a smooth transition between neighboring
+   * chrominance components in order to reduce upsampling artifacts in the
+   * decompressed image.
+   * <li> <code>1</code> Use the fastest chrominance upsampling algorithm
+   * available, which may combine upsampling with color conversion.
+   * </ul>
+   */
+  public static final int PARAM_FASTUPSAMPLE = 9;
+  /**
+   * DCT/IDCT algorithm [lossy compression and decompression]
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default]</i> Use the most accurate DCT/IDCT
+   * algorithm available.
+   * <li> <code>1</code> Use the fastest DCT/IDCT algorithm available.
+   * </ul>
+   *
+   * <p>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:
+   *
+   * <ul>
+   * <li> The "fast" and "accurate" DCT/IDCT algorithms perform similarly on
+   * modern x86/x86-64 CPUs that support AVX2 instructions.
+   * <li> The "fast" algorithm is generally only about 5-15% faster than the
+   * "accurate" algorithm on other types of CPUs.
+   * <li> 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.
+   * <li> The "fast" algorithm degrades and is not fully accelerated for JPEG
+   * quality levels above 97, so it will be slower than the "accurate"
+   * algorithm.
+   * </ul>
+   */
+  public static final int PARAM_FASTDCT = 10;
+  /**
+   * Optimized baseline entropy coding [lossy compression only]
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default]</i> The JPEG image will use the default
+   * Huffman tables.
+   * <li> <code>1</code> Optimal Huffman tables will be computed for the JPEG
+   * image.  For lossless transformation, this can also be specified using
+   * {@link TJTransform#OPT_OPTIMIZE}.
+   * </ul>
+   *
+   * <p>Optimized baseline entropy coding will improve compression slightly
+   * (generally 5% or less), but it will reduce compression performance
+   * considerably.
+   */
+  public static final int PARAM_OPTIMIZE = 11;
+  /**
+   * Progressive entropy coding
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default for compression, lossless
+   * transformation]</i> The lossy JPEG image uses (decompression) or will use
+   * (compression, lossless transformation) baseline entropy coding.
+   * <li> <code>1</code> The lossy JPEG image uses (decompression) or will use
+   * (compression, lossless transformation) progressive entropy coding.  For
+   * lossless transformation, this can also be specified using
+   * {@link TJTransform#OPT_PROGRESSIVE}.
+   * </ul>
+   *
+   * <p>Progressive entropy coding will generally improve compression relative
+   * to baseline entropy coding, but it will reduce compression and
+   * decompression performance considerably.  Can be combined with
+   * {@link #PARAM_ARITHMETIC}.  Implies {@link #PARAM_OPTIMIZE} unless
+   * {@link #PARAM_ARITHMETIC} is also set.
+   */
+  public static final int PARAM_PROGRESSIVE = 12;
+  /**
+   * Progressive JPEG scan limit for lossy JPEG images [decompression, lossless
+   * transformation]
+   *
+   * <p>Setting this parameter will cause the decompression and transform
+   * functions to return an error if the number of scans in a progressive JPEG
+   * image exceeds the specified limit.  The primary purpose of this is to
+   * allow security-critical applications to guard against an exploit of the
+   * progressive JPEG format described in
+   * <a href="https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf" target="_blank">this report</a>.
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> maximum number of progressive JPEG scans that the decompression and
+   * transform functions will process <i>[default: <code>0</code> (no
+   * limit)]</i>
+   * </ul>
+   *
+   * @see #PARAM_PROGRESSIVE
+   */
+  public static final int PARAM_SCANLIMIT = 13;
+  /**
+   * Arithmetic entropy coding
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default for compression, lossless
+   * transformation]</i> The lossy JPEG image uses (decompression) or will use
+   * (compression, lossless transformation) Huffman entropy coding.
+   * <li> <code>1</code> The lossy JPEG image uses (decompression) or will use
+   * (compression, lossless transformation) arithmetic entropy coding.  For
+   * lossless transformation, this can also be specified using
+   * {@link TJTransform#OPT_ARITHMETIC}.
+   * </ul>
+   *
+   * <p>Arithmetic entropy coding will generally improve compression relative
+   * to Huffman entropy coding, but it will reduce compression and
+   * decompression performance considerably.  Can be combined with
+   * {@link #PARAM_PROGRESSIVE}.
+   */
+  public static final int PARAM_ARITHMETIC = 14;
+  /**
+   * Lossless JPEG
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default for compression]</i> The JPEG image is
+   * (decompression) or will be (compression) lossy/DCT-based.
+   * <li> <code>1</code> The JPEG image is (decompression) or will be
+   * (compression) lossless/predictive.
+   * </ul>
+   *
+   * <p>In most cases, compressing and decompressing lossless JPEG images is
+   * considerably slower than compressing and decompressing lossy JPEG images.
+   * Also note that the following features are not available with lossless JPEG
+   * images:
+   * <ul>
+   * <li> Colorspace conversion (lossless JPEG images always use
+   * {@link #CS_RGB}, {@link #CS_GRAY}, or {@link #CS_CMYK}, depending on the
+   * pixel format of the source image)
+   * <li> Chrominance subsampling (lossless JPEG images always use
+   * {@link #SAMP_444})
+   * <li> JPEG quality selection
+   * <li> DCT/IDCT algorithm selection
+   * <li> Progressive entropy coding
+   * <li> Arithmetic entropy coding
+   * <li> Compression from/decompression to planar YUV images
+   * <li> Decompression scaling
+   * <li> Lossless transformation
+   * </ul>
+   *
+   * @see #PARAM_LOSSLESSPSV
+   * @see #PARAM_LOSSLESSPT
+   */
+  public static final int PARAM_LOSSLESS = 15;
+  /**
+   * Lossless JPEG predictor selection value (PSV)
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>1</code>-<code>7</code> <i>[default for compression:
+   * <code>1</code>]</i>
+   * </ul>
+   *
+   * @see #PARAM_LOSSLESS
+   */
+  public static final int PARAM_LOSSLESSPSV = 16;
+  /**
+   * Lossless JPEG point transform (Pt)
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> through <i><b>precision</b> - 1</i>, where
+   * <b><i>precision</i></b> is the JPEG data precision in bits <i>[default for
+   * compression: <code>0</code>]</i>
+   * </ul>
+   *
+   * <p>A point transform value of <code>0</code> 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 #PARAM_LOSSLESS
+   * @see #PARAM_PRECISION
+   */
+  public static final int PARAM_LOSSLESSPT = 17;
+  /**
+   * JPEG restart marker interval in MCU blocks (lossy) or samples (lossless)
+   * [compression only]
+   *
+   * <p>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.
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> the number of MCU blocks or samples between each restart marker
+   * <i>[default: <code>0</code> (no restart markers)]</i>
+   * </ul>
+   *
+   * <p> Setting this parameter to a non-zero value sets
+   * {@link #PARAM_RESTARTROWS} to 0.
+   */
+  public static final int PARAM_RESTARTBLOCKS = 18;
+  /**
+   * JPEG restart marker interval in MCU rows (lossy) or sample rows (lossless)
+   * [compression only]
+   *
+   * <p>See {@link #PARAM_RESTARTBLOCKS} for a description of restart markers.
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> the number of MCU rows or sample rows between each restart marker
+   * <i>[default: <code>0</code> (no restart markers)]</i>
+   * </ul>
+   *
+   * <p>Setting this parameter to a non-zero value sets
+   * {@link #PARAM_RESTARTBLOCKS} to 0.
+   */
+  public static final int PARAM_RESTARTROWS = 19;
+  /**
+   * JPEG horizontal pixel density
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> The JPEG image has (decompression) or will have (compression) the
+   * specified horizontal pixel density <i>[default for compression:
+   * <code>1</code>]</i>.
+   * </ul>
+   *
+   * <p>This value is stored in or read from the JPEG header.  It does not
+   * affect the contents of the JPEG image.
+   *
+   * @see #PARAM_DENSITYUNITS
+   */
+  public static final int PARAM_XDENSITY = 20;
+  /**
+   * JPEG vertical pixel density
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> The JPEG image has (decompression) or will have (compression) the
+   * specified vertical pixel density <i>[default for compression:
+   * <code>1</code>]</i>.
+   * </ul>
+   *
+   * <p>This value is stored in or read from the JPEG header.  It does not
+   * affect the contents of the JPEG image.
+   *
+   * @see #PARAM_DENSITYUNITS
+   */
+  public static final int PARAM_YDENSITY = 21;
+  /**
+   * JPEG pixel density units
+   *
+   * <p><b>Value</b>
+   * <ul>
+   * <li> <code>0</code> <i>[default for compression]</i> The pixel density of
+   * the JPEG image is expressed (decompression) or will be expressed
+   * (compression) in unknown units.
+   * <li> <code>1</code> The pixel density of the JPEG image is expressed
+   * (decompression) or will be expressed (compression) in units of
+   * pixels/inch.
+   * <li> <code>2</code> The pixel density of the JPEG image is expressed
+   * (decompression) or will be expressed (compression) in units of pixels/cm.
+   * </ul>
+   *
+   * <p>This value is stored in or read from the JPEG header.  It does not
+   * affect the contents of the JPEG image.
+   *
+   * @see #PARAM_XDENSITY
+   * @see #PARAM_YDENSITY
+   */
+  public static final int PARAM_DENSITYUNITS = 22;
 
-  @SuppressWarnings("checkstyle:JavadocVariable")
-  @Deprecated
-  public static final int FLAG_FORCEMMX      = 8;
-  @SuppressWarnings("checkstyle:JavadocVariable")
-  @Deprecated
-  public static final int FLAG_FORCESSE      = 16;
-  @SuppressWarnings("checkstyle:JavadocVariable")
-  @Deprecated
-  public static final int FLAG_FORCESSE2     = 32;
-  @SuppressWarnings("checkstyle:JavadocVariable")
-  @Deprecated
-  public static final int FLAG_FORCESSE3     = 128;
 
   /**
-   * When decompressing an image that was compressed using chrominance
-   * subsampling, use the fastest chrominance upsampling algorithm available in
-   * the underlying codec.  The default is to use smooth upsampling, which
-   * creates a smooth transition between neighboring chrominance components in
-   * order to reduce upsampling artifacts in the decompressed image.
+   * @deprecated Use {@link #PARAM_BOTTOMUP} instead.
    */
+  @Deprecated
+  public static final int FLAG_BOTTOMUP      = 2;
+  /**
+   * @deprecated Use {@link #PARAM_FASTUPSAMPLE} instead.
+   */
+  @Deprecated
   public static final int FLAG_FASTUPSAMPLE  = 256;
   /**
-   * Use the fastest DCT/IDCT algorithm available in the underlying codec.  The
-   * default if this flag is not specified is implementation-specific.  For
-   * example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
-   * algorithm by default when compressing, because this has been shown to have
-   * only a very slight effect on accuracy, but it uses the accurate algorithm
-   * when decompressing, because this has been shown to have a larger effect.
+   * @deprecated Use {@link #PARAM_FASTDCT} instead.
    */
+  @Deprecated
   public static final int FLAG_FASTDCT       = 2048;
   /**
-   * Use the most accurate DCT/IDCT algorithm available in the underlying
-   * codec.  The default if this flag is not specified is
-   * implementation-specific.  For example, the implementation of TurboJPEG for
-   * libjpeg[-turbo] uses the fast algorithm by default when compressing,
-   * because this has been shown to have only a very slight effect on accuracy,
-   * but it uses the accurate algorithm when decompressing, because this has
-   * been shown to have a larger effect.
+   * @deprecated Use {@link #PARAM_FASTDCT} instead.
    */
+  @Deprecated
   public static final int FLAG_ACCURATEDCT   = 4096;
   /**
-   * Immediately discontinue the current compression/decompression/transform
-   * operation if the underlying codec throws a warning (non-fatal error).  The
-   * default behavior is to allow the operation to complete unless a fatal
-   * error is encountered.
-   * <p>
-   * NOTE: due to the design of the TurboJPEG Java API, only certain methods
-   * (specifically, {@link TJDecompressor TJDecompressor.decompress*()} methods
-   * with a void return type) will complete and leave the output image in a
-   * fully recoverable state after a non-fatal error occurs.
+   * @deprecated Use {@link #PARAM_STOPONWARNING} instead.
    */
+  @Deprecated
   public static final int FLAG_STOPONWARNING = 8192;
   /**
-   * Use progressive entropy coding in JPEG images generated by compression and
-   * transform operations.  Progressive entropy coding will generally improve
-   * compression relative to baseline entropy coding (the default), but it will
-   * reduce compression and decompression performance considerably.
+   * @deprecated Use {@link #PARAM_PROGRESSIVE} instead.
    */
+  @Deprecated
   public static final int FLAG_PROGRESSIVE   = 16384;
   /**
-   * Limit the number of progressive JPEG scans that the decompression and
-   * transform operations will process.  If a progressive JPEG image contains
-   * an unreasonably large number of scans, then this flag will cause the
-   * decompression and transform operations to throw 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>.
+   * @deprecated Use {@link #PARAM_SCANLIMIT} instead.
    */
+  @Deprecated
   public static final int FLAG_LIMITSCANS    = 32768;
 
 
@@ -455,13 +818,13 @@ public final class TJ {
    */
   public static final int NUMERR = 2;
   /**
-   * The error was non-fatal and recoverable, but the image may still be
-   * corrupt.
+   * The error was non-fatal and recoverable, but the destination image may
+   * still be corrupt.
    * <p>
    * NOTE: due to the design of the TurboJPEG Java API, only certain methods
    * (specifically, {@link TJDecompressor TJDecompressor.decompress*()} methods
-   * with a void return type) will complete and leave the output image in a
-   * fully recoverable state after a non-fatal error occurs.
+   * with a void return type) will complete and leave the destination image in
+   * fully recoverable state after a non-fatal error occurs.
    */
   public static final int ERR_WARNING = 0;
   /**
@@ -479,7 +842,11 @@ public final class TJ {
    * @param height the height (in pixels) of the JPEG image
    *
    * @param jpegSubsamp the level of chrominance subsampling to be used when
-   * generating the JPEG image (one of {@link TJ TJ.SAMP_*})
+   * generating the JPEG image (one of {@link #SAMP_444 TJ.SAMP_*}.)
+   * {@link #SAMP_UNKNOWN} is treated like {@link #SAMP_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 {@link #SAMP_444}.
    *
    * @return the maximum size of the buffer (in bytes) required to hold a JPEG
    * image with the given width, height, and level of chrominance subsampling.
@@ -487,33 +854,30 @@ public final class TJ {
   public static native int bufSize(int width, int height, int jpegSubsamp);
 
   /**
-   * Returns the size of the buffer (in bytes) required to hold a YUV planar
-   * image with the given width, height, and level of chrominance subsampling.
+   * Returns the size of the buffer (in bytes) required to hold a unified
+   * planar YUV image with the given width, height, and level of chrominance
+   * subsampling.
    *
    * @param width the width (in pixels) of the YUV image
    *
-   * @param pad the width of each line in each plane of the image is padded to
-   * the nearest multiple of this number of bytes (must be a power of 2.)
+   * @param align row alignment (in bytes) of the YUV image (must be a power of
+   * 2.)  Setting this parameter to n specifies that each row in each plane of
+   * the YUV image will be padded to the nearest multiple of n bytes
+   * (1 = unpadded.)
    *
    * @param height the height (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling used in the YUV
-   * image (one of {@link TJ TJ.SAMP_*})
+   * image (one of {@link #SAMP_444 TJ.SAMP_*})
    *
-   * @return the size of the buffer (in bytes) required to hold a YUV planar
-   * image with the given width, height, and level of chrominance subsampling.
+   * @return the size of the buffer (in bytes) required to hold a unified
+   * planar YUV image with the given width, height, and level of chrominance
+   * subsampling.
    */
-  public static native int bufSizeYUV(int width, int pad, int height,
+  public static native int bufSizeYUV(int width, int align, int height,
                                       int subsamp);
 
   /**
-   * @deprecated Use {@link #bufSizeYUV(int, int, int, int)} instead.
-   */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public static native int bufSizeYUV(int width, int height, int subsamp);
-
-  /**
    * Returns the size of the buffer (in bytes) required to hold a YUV image
    * plane with the given parameters.
    *
@@ -523,23 +887,23 @@ public final class TJ {
    * @param width width (in pixels) of the YUV image.  NOTE: this is the width
    * of the whole image, not the plane width.
    *
-   * @param stride bytes per line in the image plane.
+   * @param stride bytes per row in the image plane.
    *
    * @param height height (in pixels) of the YUV image.  NOTE: this is the
    * height of the whole image, not the plane height.
    *
    * @param subsamp the level of chrominance subsampling used in the YUV
-   * image (one of {@link TJ TJ.SAMP_*})
+   * image (one of {@link #SAMP_444 TJ.SAMP_*})
    *
-   * @return the size of the buffer (in bytes) required to hold a YUV planar
-   * image with the given parameters.
+   * @return the size of the buffer (in bytes) required to hold a YUV image
+   * plane with the given parameters.
    */
   public static native int planeSizeYUV(int componentID, int width, int stride,
                                         int height, int subsamp);
 
   /**
    * Returns the plane width of a YUV image plane with the given parameters.
-   * Refer to {@link YUVImage YUVImage} for a description of plane width.
+   * Refer to {@link YUVImage} for a description of plane width.
    *
    * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb,
    * 2 = V/Cr)
@@ -547,7 +911,7 @@ public final class TJ {
    * @param width width (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling used in the YUV image
-   * (one of {@link TJ TJ.SAMP_*})
+   * (one of {@link #SAMP_444 TJ.SAMP_*})
    *
    * @return the plane width of a YUV image plane with the given parameters.
    */
@@ -555,7 +919,7 @@ public final class TJ {
 
   /**
    * Returns the plane height of a YUV image plane with the given parameters.
-   * Refer to {@link YUVImage YUVImage} for a description of plane height.
+   * Refer to {@link YUVImage} for a description of plane height.
    *
    * @param componentID ID number of the image plane (0 = Y, 1 = U/Cb,
    * 2 = V/Cr)
@@ -563,7 +927,7 @@ public final class TJ {
    * @param height height (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling used in the YUV image
-   * (one of {@link TJ TJ.SAMP_*})
+   * (one of {@link #SAMP_444 TJ.SAMP_*})
    *
    * @return the plane height of a YUV image plane with the given parameters.
    */
@@ -571,14 +935,25 @@ public final class TJ {
                                        int subsamp);
 
   /**
-   * Returns a list of fractional scaling factors that the JPEG decompressor in
-   * this implementation of TurboJPEG supports.
+   * Returns a list of fractional scaling factors that the JPEG decompressor
+   * supports.
    *
-   * @return a list of fractional scaling factors that the JPEG decompressor in
-   * this implementation of TurboJPEG supports.
+   * @return a list of fractional scaling factors that the JPEG decompressor
+   * supports.
    */
   public static native TJScalingFactor[] getScalingFactors();
 
+  /**
+   * A {@link TJScalingFactor} instance that specifies a scaling factor of 1/1
+   * (no scaling)
+   */
+  public static final TJScalingFactor UNSCALED = new TJScalingFactor(1, 1);
+
+  /**
+   * A <code>java.awt.Rectangle</code> instance that specifies no cropping
+   */
+  public static final Rectangle UNCROPPED = new Rectangle(0, 0, 0, 0);
+
   static {
     TJLoader.load();
   }
index 6d4830f..fed47de 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C)2011-2015, 2018, 2020 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2015, 2018, 2020, 2022-2023 D. R. Commander.
+ *                                               All Rights Reserved.
  * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,9 +39,6 @@ import java.io.*;
  */
 public class TJCompressor implements Closeable {
 
-  private static final String NO_ASSOC_ERROR =
-    "No source image is associated with this instance";
-
   /**
    * Create a TurboJPEG compressor instance.
    */
@@ -49,9 +47,9 @@ public class TJCompressor implements Closeable {
   }
 
   /**
-   * Create a TurboJPEG compressor instance and associate the uncompressed
-   * source image stored in <code>srcImage</code> with the newly created
-   * instance.
+   * Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+   * packed-pixel source image stored in <code>srcImage</code> with the newly
+   * created instance.
    *
    * @param srcImage see {@link #setSourceImage} for description
    *
@@ -74,20 +72,9 @@ public class TJCompressor implements Closeable {
   }
 
   /**
-   * @deprecated Use
-   * {@link #TJCompressor(byte[], int, int, int, int, int, int)} instead.
-   */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public TJCompressor(byte[] srcImage, int width, int pitch, int height,
-                      int pixelFormat) throws TJException {
-    setSourceImage(srcImage, width, pitch, height, pixelFormat);
-  }
-
-  /**
-   * Create a TurboJPEG compressor instance and associate the uncompressed
-   * source image stored in <code>srcImage</code> with the newly created
-   * instance.
+   * Create a TurboJPEG compressor instance and associate the 8-bit-per-sample
+   * packed-pixel source image stored in <code>srcImage</code> with the newly
+   * created instance.
    *
    * @param srcImage see
    * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description
@@ -110,11 +97,11 @@ public class TJCompressor implements Closeable {
   }
 
   /**
-   * Associate an uncompressed RGB, grayscale, or CMYK source image with this
-   * compressor instance.
+   * Associate an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+   * image with this compressor instance.
    *
-   * @param srcImage image buffer containing RGB, grayscale, or CMYK pixels to
-   * be compressed or encoded.  This buffer is not modified.
+   * @param srcImage buffer containing a packed-pixel RGB, grayscale, or CMYK
+   * source image to be compressed or encoded.  This buffer is not modified.
    *
    * @param x x offset (in pixels) of the region in the source image from which
    * the JPEG or YUV image should be compressed/encoded
@@ -125,14 +112,14 @@ public class TJCompressor implements Closeable {
    * @param width width (in pixels) of the region in the source image from
    * which the JPEG or YUV image should be compressed/encoded
    *
-   * @param pitch bytes per line of the source image.  Normally, this should be
-   * <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
-   * unpadded, but you can use this parameter to, for instance, specify that
-   * the scanlines in the source image are padded to a 4-byte boundary or to
-   * compress/encode a JPEG or YUV image from a region of a larger source
-   * image.  You can also be clever and use this parameter to skip lines, etc.
-   * Setting this parameter to 0 is the equivalent of setting it to
-   * <code>width * TJ.pixelSize(pixelFormat)</code>.
+   * @param pitch bytes per row in the source image.  Normally this should be
+   * <code>width * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>,
+   * if the source image is unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>width *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  However,
+   * you can also use this parameter to specify the row alignment/padding of
+   * the source image, to skip rows, or to compress/encode a JPEG or YUV image
+   * from a specific region of a larger source image.
    *
    * @param height height (in pixels) of the region in the source image from
    * which the JPEG or YUV image should be compressed/encoded
@@ -147,7 +134,7 @@ public class TJCompressor implements Closeable {
     if (srcImage == null || x < 0 || y < 0 || width < 1 || height < 1 ||
         pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
       throw new IllegalArgumentException("Invalid argument in setSourceImage()");
-    srcBuf = srcImage;
+    srcBuf8 = srcImage;
     srcWidth = width;
     if (pitch == 0)
       srcPitch = width * TJ.getPixelSize(pixelFormat);
@@ -157,28 +144,131 @@ public class TJCompressor implements Closeable {
     srcPixelFormat = pixelFormat;
     srcX = x;
     srcY = y;
+    srcBuf12 = null;
+    srcBuf16 = null;
     srcBufInt = null;
     srcYUVImage = null;
   }
 
   /**
-   * @deprecated Use
-   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} instead.
+   * Associate a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+   * image with this compressor instance.  Note that 12-bit-per-sample
+   * packed-pixel source images can only be compressed into 12-bit-per-sample
+   * JPEG images.
+   *
+   * @param srcImage buffer containing a packed-pixel RGB, grayscale, or CMYK
+   * source image to be compressed.  This buffer is not modified.
+   *
+   * @param x x offset (in pixels) of the region in the source image from which
+   * the JPEG image should be compressed
+   *
+   * @param y y offset (in pixels) of the region in the source image from which
+   * the JPEG image should be compressed
+   *
+   * @param width width (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed
+   *
+   * @param pitch samples per row in the source image.  Normally this should be
+   * <code>width * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>,
+   * if the source image is unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>width *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  However,
+   * you can also use this parameter to specify the row alignment/padding of
+   * the source image, to skip rows, or to compress a JPEG image from a
+   * specific region of a larger source image.
+   *
+   * @param height height (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed
+   *
+   * @param pixelFormat pixel format of the source image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
    */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public void setSourceImage(byte[] srcImage, int width, int pitch,
-                             int height, int pixelFormat) throws TJException {
-    setSourceImage(srcImage, 0, 0, width, pitch, height, pixelFormat);
-    srcX = srcY = -1;
+  public void setSourceImage12(short[] srcImage, int x, int y, int width,
+                               int pitch, int height, int pixelFormat)
+                               throws TJException {
+    if (handle == 0) init();
+    if (srcImage == null || x < 0 || y < 0 || width < 1 || height < 1 ||
+        pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
+    srcBuf12 = srcImage;
+    srcWidth = width;
+    if (pitch == 0)
+      srcPitch = width * TJ.getPixelSize(pixelFormat);
+    else
+      srcPitch = pitch;
+    srcHeight = height;
+    srcPixelFormat = pixelFormat;
+    srcX = x;
+    srcY = y;
+    srcBuf8 = null;
+    srcBuf16 = null;
+    srcBufInt = null;
+    srcYUVImage = null;
+  }
+
+  /**
+   * Associate a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK source
+   * image with this compressor instance.  Note that 16-bit-per-sample
+   * packed-pixel source images can only be compressed into 16-bit-per-sample
+   * lossless JPEG images.
+   *
+   * @param srcImage buffer containing a packed-pixel RGB, grayscale, or CMYK
+   * source image to be compressed.  This buffer is not modified.
+   *
+   * @param x x offset (in pixels) of the region in the source image from which
+   * the JPEG image should be compressed
+   *
+   * @param y y offset (in pixels) of the region in the source image from which
+   * the JPEG image should be compressed
+   *
+   * @param width width (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed
+   *
+   * @param pitch samples per row in the source image.  Normally this should be
+   * <code>width * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>,
+   * if the source image is unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>width *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  However,
+   * you can also use this parameter to specify the row alignment/padding of
+   * the source image, to skip rows, or to compress a JPEG image from a
+   * specific region of a larger source image.
+   *
+   * @param height height (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed
+   *
+   * @param pixelFormat pixel format of the source image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
+   */
+  public void setSourceImage16(short[] srcImage, int x, int y, int width,
+                               int pitch, int height, int pixelFormat)
+                               throws TJException {
+    if (handle == 0) init();
+    if (srcImage == null || x < 0 || y < 0 || width < 1 || height < 1 ||
+        pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
+    srcBuf16 = srcImage;
+    srcWidth = width;
+    if (pitch == 0)
+      srcPitch = width * TJ.getPixelSize(pixelFormat);
+    else
+      srcPitch = pitch;
+    srcHeight = height;
+    srcPixelFormat = pixelFormat;
+    srcX = x;
+    srcY = y;
+    srcBuf8 = null;
+    srcBuf12 = null;
+    srcBufInt = null;
+    srcYUVImage = null;
   }
 
   /**
-   * Associate an uncompressed RGB or grayscale source image with this
-   * compressor instance.
+   * Associate an 8-bit-per-pixel packed-pixel RGB or grayscale source image
+   * with this compressor instance.
    *
-   * @param srcImage a <code>BufferedImage</code> instance containing RGB or
-   * grayscale pixels to be compressed or encoded.  This image is not modified.
+   * @param srcImage a <code>BufferedImage</code> instance containing a
+   * packed-pixel RGB or grayscale source image to be compressed or encoded.
+   * This image is not modified.
    *
    * @param x x offset (in pixels) of the region in the source image from which
    * the JPEG or YUV image should be compressed/encoded
@@ -244,7 +334,7 @@ public class TJCompressor implements Closeable {
       srcStride = sm.getScanlineStride();
       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
       srcBufInt = db.getData();
-      srcBuf = null;
+      srcBuf8 = null;
     } else {
       ComponentSampleModel sm =
         (ComponentSampleModel)srcImage.getSampleModel();
@@ -253,314 +343,283 @@ public class TJCompressor implements Closeable {
         throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
       srcPitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
-      srcBuf = db.getData();
+      srcBuf8 = db.getData();
       srcBufInt = null;
     }
     srcYUVImage = null;
   }
 
   /**
-   * Associate an uncompressed YUV planar source image with this compressor
-   * instance.
+   * Associate an 8-bit-per-sample planar YUV source image with this compressor
+   * instance.  This method sets {@link TJ#PARAM_SUBSAMP} to the chrominance
+   * subsampling level of the source image.
    *
-   * @param srcImage YUV planar image to be compressed.  This image is not
-   * modified.
+   * @param srcImage planar YUV source image to be compressed.  This image is
+   * not modified.
    */
   public void setSourceImage(YUVImage srcImage) throws TJException {
     if (handle == 0) init();
     if (srcImage == null)
       throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     srcYUVImage = srcImage;
-    srcBuf = null;
+    set(TJ.PARAM_SUBSAMP, srcImage.getSubsamp());
+    srcBuf8 = null;
     srcBufInt = null;
   }
 
   /**
-   * Set the level of chrominance subsampling for subsequent compress/encode
-   * operations.  When pixels are converted from RGB to YCbCr (see
-   * {@link TJ#CS_YCbCr}) or from CMYK to YCCK (see {@link TJ#CS_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".
-   * <p>
-   * NOTE: This method has no effect when compressing a JPEG image from a YUV
-   * planar source.  In that case, the level of chrominance subsampling in
-   * the JPEG image is determined by the source.  Furthermore, this method has
-   * no effect when encoding to a pre-allocated {@link YUVImage} instance.  In
-   * that case, the level of chrominance subsampling is determined by the
-   * destination.
-   *
-   * @param newSubsamp the level of chrominance subsampling to use in
-   * subsequent compress/encode oeprations (one of
-   * {@link TJ#SAMP_444 TJ.SAMP_*})
+   * Set the value of a compression parameter.
+   *
+   * @param param one of {@link TJ#PARAM_STOPONWARNING TJ.PARAM_*}
+   *
+   * @param value value of the compression parameter (refer to
+   * {@link TJ#PARAM_STOPONWARNING parameter documentation})
+   */
+  public native void set(int param, int value);
+
+  /**
+   * Get the value of a compression parameter.
+   *
+   * @param param one of {@link TJ#PARAM_STOPONWARNING TJ.PARAM_*}
+   *
+   * @return the value of the specified compression parameter, or -1 if the
+   * value is unknown.
+   */
+  public native int get(int param);
+
+  /**
+   * @deprecated Use
+   * <code>{@link #set set}({@link TJ#PARAM_SUBSAMP}, ...)</code> instead.
    */
-  public void setSubsamp(int newSubsamp) {
-    if (newSubsamp < 0 || newSubsamp >= TJ.NUMSAMP)
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
+  public void setSubsamp(int subsamp) {
+    if (subsamp < 0 || subsamp >= TJ.NUMSAMP)
       throw new IllegalArgumentException("Invalid argument in setSubsamp()");
-    subsamp = newSubsamp;
+    set(TJ.PARAM_SUBSAMP, subsamp);
   }
 
   /**
-   * Set the JPEG image quality level for subsequent compress operations.
-   *
-   * @param quality the new JPEG image quality level (1 to 100, 1 = worst,
-   * 100 = best)
+   * @deprecated Use
+   * <code>{@link #set set}({@link TJ#PARAM_QUALITY}, ...)</code> instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public void setJPEGQuality(int quality) {
     if (quality < 1 || quality > 100)
       throw new IllegalArgumentException("Invalid argument in setJPEGQuality()");
-    jpegQuality = quality;
+    set(TJ.PARAM_QUALITY, quality);
   }
 
   /**
-   * Compress the uncompressed source image associated with this compressor
-   * instance and output a JPEG image to the given destination buffer.
+   * Compress the packed-pixel or planar YUV source image associated with this
+   * compressor instance and output a JPEG image to the given destination
+   * buffer.
    *
    * @param dstBuf buffer that will receive the JPEG image.  Use
-   * {@link TJ#bufSize} to determine the maximum size for this buffer based on
-   * the source image's width and height and the desired level of chrominance
-   * subsampling.
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * {@link TJ#bufSize TJ.bufSize()} to determine the maximum size for this
+   * buffer based on the source image's width and height and the desired level
+   * of chrominance subsampling (see {@link TJ#PARAM_SUBSAMP}.)
    */
-  public void compress(byte[] dstBuf, int flags) throws TJException {
-    if (dstBuf == null || flags < 0)
+  public void compress(byte[] dstBuf) throws TJException {
+    if (dstBuf == null)
       throw new IllegalArgumentException("Invalid argument in compress()");
-    if (srcBuf == null && srcBufInt == null && srcYUVImage == null)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (jpegQuality < 0)
-      throw new IllegalStateException("JPEG Quality not set");
-    if (subsamp < 0 && srcYUVImage == null)
-      throw new IllegalStateException("Subsampling level not set");
 
-    if (srcYUVImage != null)
-      compressedSize = compressFromYUV(srcYUVImage.getPlanes(),
-                                       srcYUVImage.getOffsets(),
-                                       srcYUVImage.getWidth(),
-                                       srcYUVImage.getStrides(),
-                                       srcYUVImage.getHeight(),
-                                       srcYUVImage.getSubsamp(),
-                                       dstBuf, jpegQuality, flags);
-    else if (srcBuf != null) {
-      if (srcX >= 0 && srcY >= 0)
-        compressedSize = compress(srcBuf, srcX, srcY, srcWidth, srcPitch,
-                                  srcHeight, srcPixelFormat, dstBuf, subsamp,
-                                  jpegQuality, flags);
-      else
-        compressedSize = compress(srcBuf, srcWidth, srcPitch, srcHeight,
-                                  srcPixelFormat, dstBuf, subsamp, jpegQuality,
-                                  flags);
-    } else if (srcBufInt != null) {
-      if (srcX >= 0 && srcY >= 0)
-        compressedSize = compress(srcBufInt, srcX, srcY, srcWidth, srcStride,
-                                  srcHeight, srcPixelFormat, dstBuf, subsamp,
-                                  jpegQuality, flags);
-      else
-        compressedSize = compress(srcBufInt, srcWidth, srcStride, srcHeight,
-                                  srcPixelFormat, dstBuf, subsamp, jpegQuality,
-                                  flags);
-    }
+    if (srcYUVImage != null) {
+      checkSubsampling();
+      if (get(TJ.PARAM_SUBSAMP) != srcYUVImage.getSubsamp())
+        throw new IllegalStateException("TJ.PARAM_SUBSAMP must match subsampling level of YUV image");
+      compressedSize = compressFromYUV8(srcYUVImage.getPlanes(),
+                                        srcYUVImage.getOffsets(),
+                                        srcYUVImage.getWidth(),
+                                        srcYUVImage.getStrides(),
+                                        srcYUVImage.getHeight(), dstBuf);
+    } else if (srcBuf8 != null)
+      compressedSize = compress8(srcBuf8, srcX, srcY, srcWidth, srcPitch,
+                                 srcHeight, srcPixelFormat, dstBuf);
+    else if (srcBuf12 != null)
+      compressedSize = compress12(srcBuf12, srcX, srcY, srcWidth, srcPitch,
+                                  srcHeight, srcPixelFormat, dstBuf);
+    else if (srcBuf16 != null)
+      compressedSize = compress16(srcBuf16, srcX, srcY, srcWidth, srcPitch,
+                                  srcHeight, srcPixelFormat, dstBuf);
+    else if (srcBufInt != null)
+      compressedSize = compress8(srcBufInt, srcX, srcY, srcWidth, srcStride,
+                                 srcHeight, srcPixelFormat, dstBuf);
+    else
+      throw new IllegalStateException("No source image is associated with this instance");
   }
 
   /**
-   * Compress the uncompressed source image associated with this compressor
-   * instance and return a buffer containing a JPEG image.
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * @deprecated Use {@link #set set()} and {@link #compress(byte[])} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
+  public void compress(byte[] dstBuf, int flags) throws TJException {
+    if (flags < 0)
+      throw new IllegalArgumentException("Invalid argument in compress()");
+    processFlags(flags);
+    compress(dstBuf);
+  }
+
+  /**
+   * Compress the packed-pixel or planar YUV source image associated with this
+   * compressor instance and return a buffer containing a JPEG image.
    *
    * @return a buffer containing a JPEG image.  The length of this buffer will
-   * not be equal to the size of the JPEG image.  Use {@link
-   * #getCompressedSize} to obtain the size of the JPEG image.
+   * not be equal to the size of the JPEG image.  Use
+   * {@link #getCompressedSize} to obtain the size of the JPEG image.
    */
-  public byte[] compress(int flags) throws TJException {
+  public byte[] compress() throws TJException {
     byte[] buf;
     if (srcYUVImage != null) {
       buf = new byte[TJ.bufSize(srcYUVImage.getWidth(),
                                 srcYUVImage.getHeight(),
                                 srcYUVImage.getSubsamp())];
     } else {
-      checkSourceImage();
+      checkSubsampling();
+      int subsamp = get(TJ.PARAM_SUBSAMP);
       buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)];
     }
-    compress(buf, flags);
+    compress(buf);
     return buf;
   }
 
   /**
-   * @deprecated Use
-   * {@link #setSourceImage(BufferedImage, int, int, int, int)} and
-   * {@link #compress(byte[], int)} instead.
-   */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public void compress(BufferedImage srcImage, byte[] dstBuf, int flags)
-                       throws TJException {
-    setSourceImage(srcImage, 0, 0, 0, 0);
-    compress(dstBuf, flags);
-  }
-
-  /**
-   * @deprecated Use
-   * {@link #setSourceImage(BufferedImage, int, int, int, int)} and
-   * {@link #compress(int)} instead.
+   * @deprecated Use {@link #set set()} and {@link #compress()} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public byte[] compress(BufferedImage srcImage, int flags)
-                         throws TJException {
-    setSourceImage(srcImage, 0, 0, 0, 0);
-    return compress(flags);
+  public byte[] compress(int flags) throws TJException {
+    processFlags(flags);
+    return compress();
   }
 
   /**
-   * Encode the uncompressed source image associated with this compressor
-   * instance into a YUV planar image and store it in the given
-   * <code>YUVImage</code> instance.   This method uses the accelerated color
-   * conversion routines in TurboJPEG's underlying codec but does not execute
-   * any of the other steps in the JPEG compression process.  Encoding
-   * CMYK source images to YUV is not supported.
-   *
-   * @param dstImage {@link YUVImage} instance that will receive the YUV planar
+   * Encode the 8-bit-per-sample packed-pixel source image associated with this
+   * compressor instance into an 8-bit-per-sample planar YUV image and store it
+   * in the given {@link YUVImage} instance.  This method 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.
+   * Encoding CMYK source images into YUV images is not supported.  This method
+   * sets {@link TJ#PARAM_SUBSAMP} to the chrominance subsampling level of the
+   * destination image.
+   *
+   * @param dstImage {@link YUVImage} instance that will receive the planar YUV
    * image
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
-  public void encodeYUV(YUVImage dstImage, int flags) throws TJException {
-    if (dstImage == null || flags < 0)
+  public void encodeYUV(YUVImage dstImage) throws TJException {
+    if (dstImage == null)
       throw new IllegalArgumentException("Invalid argument in encodeYUV()");
-    if (srcBuf == null && srcBufInt == null)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
+    if (srcBuf8 == null && srcBufInt == null)
+      throw new IllegalStateException("No 8-bit-per-sample source image is associated with this instance");
     if (srcYUVImage != null)
       throw new IllegalStateException("Source image is not correct type");
-    checkSubsampling();
     if (srcWidth != dstImage.getWidth() || srcHeight != dstImage.getHeight())
       throw new IllegalStateException("Destination image is the wrong size");
+    set(TJ.PARAM_SUBSAMP, dstImage.getSubsamp());
 
     if (srcBufInt != null) {
-      encodeYUV(srcBufInt, srcX, srcY, srcWidth, srcStride, srcHeight,
-                srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
-                dstImage.getStrides(), dstImage.getSubsamp(), flags);
+      encodeYUV8(srcBufInt, srcX, srcY, srcWidth, srcStride, srcHeight,
+                 srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
+                 dstImage.getStrides());
     } else {
-      encodeYUV(srcBuf, srcX, srcY, srcWidth, srcPitch, srcHeight,
-                srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
-                dstImage.getStrides(), dstImage.getSubsamp(), flags);
+      encodeYUV8(srcBuf8, srcX, srcY, srcWidth, srcPitch, srcHeight,
+                 srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(),
+                 dstImage.getStrides());
     }
     compressedSize = 0;
   }
 
   /**
-   * @deprecated Use {@link #encodeYUV(YUVImage, int)} instead.
+   * @deprecated Use {@link #set set()} and {@link #encodeYUV(YUVImage)}
+   * instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public void encodeYUV(byte[] dstBuf, int flags) throws TJException {
-    if (dstBuf == null)
+  public void encodeYUV(YUVImage dstImage, int flags) throws TJException {
+    if (flags < 0)
       throw new IllegalArgumentException("Invalid argument in encodeYUV()");
-    checkSourceImage();
-    checkSubsampling();
-    YUVImage dstYUVImage = new YUVImage(dstBuf, srcWidth, 4, srcHeight,
-                                        subsamp);
-    encodeYUV(dstYUVImage, flags);
-  }
 
-  /**
-   * Encode the uncompressed source image associated with this compressor
-   * instance into a unified YUV planar image buffer and return a
-   * <code>YUVImage</code> instance containing the encoded image.  This method
-   * uses the accelerated color conversion routines in TurboJPEG's underlying
-   * codec but does not execute any of the other steps in the JPEG compression
-   * process.  Encoding CMYK source images to YUV is not supported.
-   *
-   * @param pad the width of each line in each plane of the YUV image will be
-   * padded to the nearest multiple of this number of bytes (must be a power of
-   * 2.)
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
-   *
-   * @return a YUV planar image.
-   */
-  public YUVImage encodeYUV(int pad, int flags) throws TJException {
-    checkSourceImage();
-    checkSubsampling();
-    if (pad < 1 || ((pad & (pad - 1)) != 0))
-      throw new IllegalStateException("Invalid argument in encodeYUV()");
-    YUVImage dstYUVImage = new YUVImage(srcWidth, pad, srcHeight, subsamp);
-    encodeYUV(dstYUVImage, flags);
-    return dstYUVImage;
+    processFlags(flags);
+    encodeYUV(dstImage);
   }
 
   /**
-   * Encode the uncompressed source image associated with this compressor
-   * instance into separate Y, U (Cb), and V (Cr) image planes and return a
-   * <code>YUVImage</code> instance containing the encoded image planes.  This
-   * method uses the accelerated color conversion routines in TurboJPEG's
-   * underlying codec but does not execute any of the other steps in the JPEG
-   * compression process.  Encoding CMYK source images to YUV is not supported.
-   *
-   * @param strides an array of integers, each specifying the number of bytes
-   * per line in the corresponding plane of the output image.  Setting the
-   * stride for any plane to 0 is the same as setting it to the component width
-   * of the plane.  If <code>strides</code> is null, then the strides for all
-   * planes will be set to their respective component widths.  You can adjust
-   * the strides in order to add an arbitrary amount of line padding to each
-   * plane.
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
-   *
-   * @return a YUV planar image.
+   * Encode the 8-bit-per-sample packed-pixel source image associated with this
+   * compressor instance into an 8-bit-per-sample unified planar YUV image and
+   * return a {@link YUVImage} instance containing the encoded image.  This
+   * method 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.  Encoding CMYK source images into YUV
+   * images is not supported.
+   *
+   * @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.)
+   *
+   * @return a {@link YUVImage} instance containing the unified planar YUV
+   * encoded image
    */
-  public YUVImage encodeYUV(int[] strides, int flags) throws TJException {
-    checkSourceImage();
+  public YUVImage encodeYUV(int align) throws TJException {
+    if (srcBuf8 == null && srcBufInt == null)
+      throw new IllegalStateException("No 8-bit-per-sample source image is associated with this instance");
     checkSubsampling();
-    YUVImage dstYUVImage = new YUVImage(srcWidth, strides, srcHeight, subsamp);
-    encodeYUV(dstYUVImage, flags);
+    if (align < 1 || ((align & (align - 1)) != 0))
+      throw new IllegalStateException("Invalid argument in encodeYUV()");
+    YUVImage dstYUVImage = new YUVImage(srcWidth, align, srcHeight,
+                                        get(TJ.PARAM_SUBSAMP));
+    encodeYUV(dstYUVImage);
     return dstYUVImage;
   }
 
   /**
-   * @deprecated Use {@link #encodeYUV(int, int)} instead.
+   * @deprecated Use {@link #set set()} and {@link #encodeYUV(int)} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public byte[] encodeYUV(int flags) throws TJException {
-    checkSourceImage();
-    checkSubsampling();
-    YUVImage dstYUVImage = new YUVImage(srcWidth, 4, srcHeight, subsamp);
-    encodeYUV(dstYUVImage, flags);
-    return dstYUVImage.getBuf();
+  public YUVImage encodeYUV(int align, int flags) throws TJException {
+    processFlags(flags);
+    return encodeYUV(align);
   }
 
   /**
-   * @deprecated Use
-   * {@link #setSourceImage(BufferedImage, int, int, int, int)} and
-   * {@link #encodeYUV(byte[], int)} instead.
+   * Encode the 8-bit-per-sample packed-pixel source image associated with this
+   * compressor instance into separate 8-bit-per-sample Y, U (Cb), and V (Cr)
+   * image planes and return a {@link YUVImage} instance containing the encoded
+   * image planes.  This method 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.  Encoding CMYK source images into
+   * YUV images is not supported.
+   *
+   * @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 {@link YUVImage}.)  If <code>strides</code> 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.
+   *
+   * @return a {@link YUVImage} instance containing the encoded image planes
    */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags)
-                        throws TJException {
-    setSourceImage(srcImage, 0, 0, 0, 0);
-    encodeYUV(dstBuf, flags);
+  public YUVImage encodeYUV(int[] strides) throws TJException {
+    if (srcBuf8 == null && srcBufInt == null)
+      throw new IllegalStateException("No 8-bit-per-sample source image is associated with this instance");
+    checkSubsampling();
+    YUVImage dstYUVImage = new YUVImage(srcWidth, strides, srcHeight,
+                                        get(TJ.PARAM_SUBSAMP));
+    encodeYUV(dstYUVImage);
+    return dstYUVImage;
   }
 
   /**
-   * @deprecated Use
-   * {@link #setSourceImage(BufferedImage, int, int, int, int)} and
-   * {@link #encodeYUV(int, int)} instead.
+   * @deprecated Use {@link #set set()} and {@link #encodeYUV(int[])} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public byte[] encodeYUV(BufferedImage srcImage, int flags)
-                          throws TJException {
-    setSourceImage(srcImage, 0, 0, 0, 0);
-    return encodeYUV(flags);
+  public YUVImage encodeYUV(int[] strides, int flags) throws TJException {
+    processFlags(flags);
+    return encodeYUV(strides);
   }
 
   /**
@@ -594,79 +653,82 @@ public class TJCompressor implements Closeable {
     }
   };
 
+  @SuppressWarnings("deprecation")
+  private void processFlags(int flags) {
+    set(TJ.PARAM_BOTTOMUP, (flags & TJ.FLAG_BOTTOMUP) != 0 ? 1 : 0);
+
+    if (get(TJ.PARAM_QUALITY) >= 96 || (flags & TJ.FLAG_ACCURATEDCT) != 0)
+      set(TJ.PARAM_FASTDCT, 0);
+    else
+      set(TJ.PARAM_FASTDCT, 1);
+
+    set(TJ.PARAM_STOPONWARNING, (flags & TJ.FLAG_STOPONWARNING) != 0 ? 1 : 0);
+    set(TJ.PARAM_PROGRESSIVE, (flags & TJ.FLAG_PROGRESSIVE) != 0 ? 1 : 0);
+  }
+
+  private void checkSubsampling() {
+    if (get(TJ.PARAM_SUBSAMP) == TJ.SAMP_UNKNOWN)
+      throw new IllegalStateException("TJ.PARAM_SUBSAMP must be specified");
+  }
+
   private native void init() throws TJException;
 
   private native void destroy() throws TJException;
 
   // JPEG size in bytes is returned
   @SuppressWarnings("checkstyle:HiddenField")
-  @Deprecated
-  private native int compress(byte[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] jpegBuf, int jpegSubsamp, int jpegQual,
-    int flags) throws TJException;
-
-  @SuppressWarnings("checkstyle:HiddenField")
-  private native int compress(byte[] srcBuf, int x, int y, int width,
-    int pitch, int height, int pixelFormat, byte[] jpegBuf, int jpegSubsamp,
-    int jpegQual, int flags) throws TJException;
+  private native int compress8(byte[] srcBuf, int x, int y, int width,
+    int pitch, int height, int pixelFormat, byte[] jpegBuf) throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  @Deprecated
-  private native int compress(int[] srcBuf, int width, int stride,
-    int height, int pixelFormat, byte[] jpegBuf, int jpegSubsamp, int jpegQual,
-    int flags) throws TJException;
+  private native int compress12(short[] srcBuf, int x, int y, int width,
+    int pitch, int height, int pixelFormat, byte[] jpegBuf) throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  private native int compress(int[] srcBuf, int x, int y, int width,
-    int stride, int height, int pixelFormat, byte[] jpegBuf, int jpegSubsamp,
-    int jpegQual, int flags) throws TJException;
+  private native int compress16(short[] srcBuf, int x, int y, int width,
+    int pitch, int height, int pixelFormat, byte[] jpegBuf) throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  private native int compressFromYUV(byte[][] srcPlanes, int[] srcOffsets,
-    int width, int[] srcStrides, int height, int subsamp, byte[] jpegBuf,
-    int jpegQual, int flags)
+  private native int compress8(int[] srcBuf, int x, int y, int width,
+    int stride, int height, int pixelFormat, byte[] jpegBuf)
     throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  @Deprecated
-  private native void encodeYUV(byte[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
+  private native int compressFromYUV8(byte[][] srcPlanes, int[] srcOffsets,
+    int width, int[] srcStrides, int height, byte[] jpegBuf)
     throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  private native void encodeYUV(byte[] srcBuf, int x, int y, int width,
+  private native void encodeYUV8(byte[] srcBuf, int x, int y, int width,
     int pitch, int height, int pixelFormat, byte[][] dstPlanes,
-    int[] dstOffsets, int[] dstStrides, int subsamp, int flags)
-    throws TJException;
-
-  @SuppressWarnings("checkstyle:HiddenField")
-  @Deprecated
-  private native void encodeYUV(int[] srcBuf, int width, int stride,
-    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
-    throws TJException;
+    int[] dstOffsets, int[] dstStrides) throws TJException;
 
   @SuppressWarnings("checkstyle:HiddenField")
-  private native void encodeYUV(int[] srcBuf, int x, int y, int width,
+  private native void encodeYUV8(int[] srcBuf, int x, int y, int width,
     int srcStride, int height, int pixelFormat, byte[][] dstPlanes,
-    int[] dstOffsets, int[] dstStrides, int subsamp, int flags)
-    throws TJException;
+    int[] dstOffsets, int[] dstStrides) throws TJException;
+
+  /**
+   * @hidden
+   * Ugly hack alert.  It isn't straightforward to load 12-bit-per-sample and
+   * 16-bit-per-sample images using the ImageIO and BufferedImage classes, and
+   * ImageIO doesn't support PBMPLUS files anyhow.  This method accesses
+   * tj3LoadImage() through JNI and copies the pixel data between the C and
+   * Java heaps.  Currently it is undocumented and used only by TJBench.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  public native Object loadImage(int precision, String fileName, int[] width,
+                                 int align, int[] height, int[] pixelFormat)
+                                 throws TJException;
 
   static {
     TJLoader.load();
   }
 
-  private void checkSourceImage() {
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-  }
-
-  private void checkSubsampling() {
-    if (subsamp < 0)
-      throw new IllegalStateException("Subsampling level not set");
-  }
-
   private long handle = 0;
-  private byte[] srcBuf = null;
+  private byte[] srcBuf8 = null;
+  private short[] srcBuf12 = null;
+  private short[] srcBuf16 = null;
   private int[] srcBufInt = null;
   private int srcWidth = 0;
   private int srcHeight = 0;
@@ -676,9 +738,6 @@ public class TJCompressor implements Closeable {
   private int srcStride = 0;
   private int srcPixelFormat = -1;
   private YUVImage srcYUVImage = null;
-  private int subsamp = -1;
-  private int jpegQuality = -1;
   private int compressedSize = 0;
-  private int yuvPad = 4;
   private ByteOrder byteOrder = null;
 }
index 9a34587..78e6e4e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011, 2013 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011, 2013, 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:
@@ -58,13 +58,13 @@ public interface TJCustomFilter {
    * component plane to which <code>coeffBuffer</code> belongs
    *
    * @param componentID ID number of the component plane to which
-   * <code>coeffBuffer</code> belongs (Y, Cb, and Cr have, respectively, ID's
+   * <code>coeffBuffer</code> 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
    * <code>coeffBuffer</code> belongs.  This is the same as the index of the
-   * transform in the <code>transforms</code> array that was passed to {@link
-   * TJTransformer#transform TJTransformer.transform()}.
+   * transform in the <code>transforms</code> array that was passed to
+   * {@link TJTransformer#transform TJTransformer.transform()}.
    *
    * @param transform a {@link TJTransform} instance that specifies the
    * parameters and/or cropping region for this transform
index aba390b..d8c0545 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C)2011-2015, 2018, 2022 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2015, 2018, 2022-2023 D. R. Commander.
+ *                                         All Rights Reserved.
  * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,6 +30,7 @@
 
 package org.libjpegturbo.turbojpeg;
 
+import java.awt.Rectangle;
 import java.awt.image.*;
 import java.nio.*;
 import java.io.*;
@@ -50,10 +52,13 @@ public class TJDecompressor implements Closeable {
 
   /**
    * Create a TurboJPEG decompressor instance and associate the JPEG source
-   * image stored in <code>jpegImage</code> with the newly created instance.
+   * image or "abbreviated table specification" (AKA "tables-only") datastream
+   * stored in <code>jpegImage</code> with the newly created instance.  Refer
+   * to {@link #setSourceImage(byte[], int)} for more details.
    *
-   * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
-   * be the length of the array.)  This buffer is not modified.
+   * @param jpegImage buffer containing a JPEG source image or tables-only
+   * datastream.  (The size of the JPEG image or datastream is assumed to be
+   * the length of the array.)  This buffer is not modified.
    */
   public TJDecompressor(byte[] jpegImage) throws TJException {
     init();
@@ -62,12 +67,16 @@ public class TJDecompressor implements Closeable {
 
   /**
    * Create a TurboJPEG decompressor instance and associate the JPEG source
-   * image of length <code>imageSize</code> bytes stored in
-   * <code>jpegImage</code> with the newly created instance.
+   * image or "abbreviated table specification" (AKA "tables-only") datastream
+   * of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
+   * with the newly created instance.  Refer to
+   * {@link #setSourceImage(byte[], int)} for more details.
    *
-   * @param jpegImage JPEG image buffer.  This buffer is not modified.
+   * @param jpegImage buffer containing a JPEG source image or tables-only
+   * datastream.  This buffer is not modified.
    *
-   * @param imageSize size of the JPEG image (in bytes)
+   * @param imageSize size of the JPEG source image or tables-only datastream
+   * (in bytes)
    */
   public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
     init();
@@ -75,11 +84,12 @@ public class TJDecompressor implements Closeable {
   }
 
   /**
-   * Create a TurboJPEG decompressor instance and associate the YUV planar
-   * source image stored in <code>yuvImage</code> with the newly created
-   * instance.
+   * Create a TurboJPEG decompressor instance and associate the
+   * 8-bit-per-sample planar YUV source image stored in <code>yuvImage</code>
+   * with the newly created instance.  Refer to
+   * {@link #setSourceImage(YUVImage)} for more details.
    *
-   * @param yuvImage {@link YUVImage} instance containing a YUV planar
+   * @param yuvImage {@link YUVImage} instance containing a planar YUV source
    * image to be decoded.  This image is not modified.
    */
   @SuppressWarnings("checkstyle:HiddenField")
@@ -93,18 +103,20 @@ public class TJDecompressor implements Closeable {
    * "tables-only") datastream of length <code>imageSize</code> bytes stored in
    * <code>jpegImage</code> with this decompressor instance.  If
    * <code>jpegImage</code> contains a JPEG image, then this image will be used
-   * as the source image for subsequent decompress operations.  Passing a
+   * as the source image for subsequent decompression operations.  Passing a
    * tables-only datastream to this method 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.
+   * quantization and Huffman tables.  If a JPEG image is passed to this
+   * method, then the {@link TJ#PARAM_STOPONWARNING parameters} that describe
+   * the JPEG image will be set when the method returns.
    *
-   * @param jpegImage buffer containing a JPEG image or an "abbreviated table
-   * specification" (AKA "tables-only") datastream.  This buffer is not
-   * modified.
+   * @param jpegImage buffer containing a JPEG source image or tables-only
+   * datastream.  This buffer is not modified.
    *
-   * @param imageSize size of the JPEG image (in bytes)
+   * @param imageSize size of the JPEG source image or tables-only datastream
+   * (in bytes)
    */
   public void setSourceImage(byte[] jpegImage, int imageSize)
                              throws TJException {
@@ -117,27 +129,20 @@ public class TJDecompressor implements Closeable {
   }
 
   /**
-   * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
-   */
-  @SuppressWarnings("checkstyle:JavadocMethod")
-  @Deprecated
-  public void setJPEGImage(byte[] jpegImage, int imageSize)
-                           throws TJException {
-    setSourceImage(jpegImage, imageSize);
-  }
-
-  /**
-   * Associate the specified YUV planar source image with this decompressor
-   * instance.  Subsequent decompress operations will decode this image into an
-   * RGB or grayscale destination image.
+   * Associate the specified planar YUV source image with this decompressor
+   * instance.  Subsequent decompression operations will decode this image into
+   * a packed-pixel RGB or grayscale destination image.  This method sets
+   * {@link TJ#PARAM_SUBSAMP} to the chrominance subsampling level of the
+   * source image.
    *
-   * @param srcImage {@link YUVImage} instance containing a YUV planar image to
-   * be decoded.  This image is not modified.
+   * @param srcImage {@link YUVImage} instance containing a planar YUV source
+   * image to be decoded.  This image is not modified.
    */
   public void setSourceImage(YUVImage srcImage) {
     if (srcImage == null)
       throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     yuvImage = srcImage;
+    set(TJ.PARAM_SUBSAMP, srcImage.getSubsamp());
     jpegBuf = null;
     jpegBufSize = 0;
   }
@@ -153,6 +158,11 @@ public class TJDecompressor implements Closeable {
   public int getWidth() {
     if (yuvImage != null)
       return yuvImage.getWidth();
+    return getJPEGWidth();
+  }
+
+  private int getJPEGWidth() {
+    int jpegWidth = get(TJ.PARAM_JPEGWIDTH);
     if (jpegWidth < 1)
       throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegWidth;
@@ -168,40 +178,125 @@ public class TJDecompressor implements Closeable {
   public int getHeight() {
     if (yuvImage != null)
       return yuvImage.getHeight();
+    return getJPEGHeight();
+  }
+
+  private int getJPEGHeight() {
+    int jpegHeight = get(TJ.PARAM_JPEGHEIGHT);
     if (jpegHeight < 1)
       throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegHeight;
   }
 
   /**
-   * Returns the level of chrominance subsampling used in the source image
-   * (JPEG or YUV) associated with this decompressor instance.  See
-   * {@link TJ#SAMP_444 TJ.SAMP_*}.
+   * Set the value of a decompression parameter.
+   *
+   * @param param one of {@link TJ#PARAM_STOPONWARNING TJ.PARAM_*}
+   *
+   * @param value value of the decompression parameter (refer to
+   * {@link TJ#PARAM_STOPONWARNING parameter documentation})
+   */
+  public native void set(int param, int value);
+
+  /**
+   * Get the value of a decompression parameter.
    *
-   * @return the level of chrominance subsampling used in the source image
-   * (JPEG or YUV) associated with this decompressor instance.
+   * @param param one of {@link TJ#PARAM_STOPONWARNING TJ.PARAM_*}
+   *
+   * @return the value of the specified decompression parameter, or -1 if the
+   * value is unknown.
+   */
+  public native int get(int param);
+
+  /**
+   * Set the scaling factor for subsequent lossy decompression operations.
+   *
+   * @param scalingFactor {@link TJScalingFactor} instance that specifies a
+   * fractional scaling factor that the decompressor supports (see
+   * {@link TJ#getScalingFactors}), or {@link TJ#UNSCALED} 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
+   * <code>scalingFactor.</code>{@link TJScalingFactor#getScaled getScaled()}
+   * with the JPEG image width and height (see {@link #getWidth} and
+   * {@link #getHeight}.)  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 MCU block size
+   * (see {@link TJ#getMCUWidth TJ.getMCUWidth()} and {@link TJ#getMCUHeight
+   * TJ.getMCUHeight()}.)  Note that decompression scaling is not available
+   * (and the specified scaling factor is ignored) when decompressing lossless
+   * JPEG images (see {@link TJ#PARAM_LOSSLESS}), since the IDCT algorithm is
+   * not used with those images.  Note also that {@link TJ#PARAM_FASTDCT} is
+   * ignored when decompression scaling is enabled.
+   */
+  @SuppressWarnings("checkstyle:HiddenField")
+  public void setScalingFactor(TJScalingFactor scalingFactor) {
+    if (scalingFactor == null)
+      throw new IllegalArgumentException("Invalid argument in setScalingFactor()");
+
+    TJScalingFactor[] sf = TJ.getScalingFactors();
+    int i;
+    for (i = 0; i < sf.length; i++) {
+      if (scalingFactor.getNum() == sf[i].getNum() &&
+          scalingFactor.getDenom() == sf[i].getDenom())
+        break;
+    }
+    if (i >= sf.length)
+      throw new IllegalArgumentException("Unsupported scaling factor");
+
+    this.scalingFactor = scalingFactor;
+  }
+
+  /**
+   * Set the cropping region for partially decompressing a lossy JPEG image
+   * into a packed-pixel image.
+   *
+   * @param croppingRegion <code>java.awt.Rectangle</code> instance that
+   * specifies a subregion of the JPEG image to decompress, or
+   * {@link TJ#UNCROPPED} for no cropping.  The left boundary of the cropping
+   * region must be evenly divisible by the scaled MCU block width, which can
+   * be determined by calling {@link TJScalingFactor#getScaled
+   * TJScalingFactor.getScaled()} with the specified scaling factor (see
+   * {@link #setScalingFactor setScalingFactor()}) and the MCU block width
+   * (see {@link TJ#getMCUWidth TJ.getMCUWidth()}) for the level of chrominance
+   * subsampling in the JPEG image (see {@link TJ#PARAM_SUBSAMP}.)  The
+   * cropping region should be specified relative to the scaled image
+   * dimensions.  Unless <code>croppingRegion</code> is {@link TJ#UNCROPPED},
+   * the JPEG header must be read (see {@link #setSourceImage(byte[], int)}
+   * prior to calling this method.
+   */
+  @SuppressWarnings("checkstyle:HiddenField")
+  public void setCroppingRegion(Rectangle croppingRegion) throws TJException {
+    this.croppingRegion = croppingRegion;
+    setCroppingRegion();
+  }
+
+  /**
+   * @deprecated Use <code>{@link #get get}({@link TJ#PARAM_SUBSAMP})</code>
+   * instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public int getSubsamp() {
-    if (yuvImage != null)
-      return yuvImage.getSubsamp();
-    if (jpegSubsamp < 0)
+    int subsamp = get(TJ.PARAM_SUBSAMP);
+    if (subsamp == TJ.SAMP_UNKNOWN)
       throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (jpegSubsamp >= TJ.NUMSAMP)
+    if (subsamp >= TJ.NUMSAMP)
       throw new IllegalStateException("JPEG header information is invalid");
-    return jpegSubsamp;
+    return subsamp;
   }
 
   /**
-   * Returns the colorspace used in the source image (JPEG or YUV) associated
-   * with this decompressor instance.  See {@link TJ#CS_RGB TJ.CS_*}.  If the
-   * source image is YUV, then this always returns {@link TJ#CS_YCbCr}.
-   *
-   * @return the colorspace used in the source image (JPEG or YUV) associated
-   * with this decompressor instance.
+   * @deprecated Use <code>{@link #get get}({@link TJ#PARAM_COLORSPACE})</code>
+   * instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public int getColorspace() {
     if (yuvImage != null)
       return TJ.CS_YCbCr;
+    int jpegColorspace = get(TJ.PARAM_COLORSPACE);
     if (jpegColorspace < 0)
       throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegColorspace >= TJ.NUMCS)
@@ -210,9 +305,9 @@ public class TJDecompressor implements Closeable {
   }
 
   /**
-   * Returns the JPEG image buffer associated with this decompressor instance.
+   * Returns the JPEG buffer associated with this decompressor instance.
    *
-   * @return the JPEG image buffer associated with this decompressor instance.
+   * @return the JPEG buffer associated with this decompressor instance.
    */
   public byte[] getJPEGBuf() {
     if (jpegBuf == null)
@@ -234,109 +329,75 @@ public class TJDecompressor implements Closeable {
   }
 
   /**
-   * Returns the width of the largest scaled-down image that the TurboJPEG
-   * decompressor can generate without exceeding the desired image width and
-   * height.
-   *
-   * @param desiredWidth desired width (in pixels) of the decompressed image.
-   * Setting this to 0 is the same as setting it to the width of the JPEG image
-   * (in other words, the width will not be considered when determining the
-   * scaled image size.)
-   *
-   * @param desiredHeight desired height (in pixels) of the decompressed image.
-   * Setting this to 0 is the same as setting it to the height of the JPEG
-   * image (in other words, the height will not be considered when determining
-   * the scaled image size.)
-   *
-   * @return the width of the largest scaled-down image that the TurboJPEG
-   * decompressor can generate without exceeding the desired image width and
-   * height.
+   * @deprecated Use {@link #setScalingFactor setScalingFactor()} and
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()} instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public int getScaledWidth(int desiredWidth, int desiredHeight) {
-    if (jpegWidth < 1 || jpegHeight < 1)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (desiredWidth < 0 || desiredHeight < 0)
-      throw new IllegalArgumentException("Invalid argument in getScaledWidth()");
-    TJScalingFactor[] sf = TJ.getScalingFactors();
-    if (desiredWidth == 0)
-      desiredWidth = jpegWidth;
-    if (desiredHeight == 0)
-      desiredHeight = jpegHeight;
-    int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
-    for (int i = 0; i < sf.length; i++) {
-      scaledWidth = sf[i].getScaled(jpegWidth);
-      scaledHeight = sf[i].getScaled(jpegHeight);
-      if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
-        break;
-    }
-    if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
-      throw new IllegalArgumentException("Could not scale down to desired image dimensions");
-    return scaledWidth;
+    TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+    return sf.getScaled(getJPEGWidth());
   }
 
   /**
-   * Returns the height of the largest scaled-down image that the TurboJPEG
-   * decompressor can generate without exceeding the desired image width and
-   * height.
-   *
-   * @param desiredWidth desired width (in pixels) of the decompressed image.
-   * Setting this to 0 is the same as setting it to the width of the JPEG image
-   * (in other words, the width will not be considered when determining the
-   * scaled image size.)
-   *
-   * @param desiredHeight desired height (in pixels) of the decompressed image.
-   * Setting this to 0 is the same as setting it to the height of the JPEG
-   * image (in other words, the height will not be considered when determining
-   * the scaled image size.)
-   *
-   * @return the height of the largest scaled-down image that the TurboJPEG
-   * decompressor can generate without exceeding the desired image width and
-   * height.
+   * @deprecated Use {@link #setScalingFactor setScalingFactor()} and
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()} instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public int getScaledHeight(int desiredWidth, int desiredHeight) {
-    if (jpegWidth < 1 || jpegHeight < 1)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
+    TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+    return sf.getScaled(getJPEGHeight());
+  }
+
+  private TJScalingFactor getScalingFactor(int desiredWidth,
+                                           int desiredHeight) {
+    int jpegWidth = getJPEGWidth();
+    int jpegHeight = getJPEGHeight();
     if (desiredWidth < 0 || desiredHeight < 0)
-      throw new IllegalArgumentException("Invalid argument in getScaledHeight()");
+      throw new IllegalArgumentException("Invalid argument");
+
     TJScalingFactor[] sf = TJ.getScalingFactors();
+
     if (desiredWidth == 0)
       desiredWidth = jpegWidth;
     if (desiredHeight == 0)
       desiredHeight = jpegHeight;
-    int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
-    for (int i = 0; i < sf.length; i++) {
-      scaledWidth = sf[i].getScaled(jpegWidth);
-      scaledHeight = sf[i].getScaled(jpegHeight);
-      if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
+    int i;
+    for (i = 0; i < sf.length; i++) {
+      if (sf[i].getScaled(jpegWidth) <= desiredWidth &&
+          sf[i].getScaled(jpegHeight) <= desiredHeight)
         break;
     }
-    if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
+    if (i >= sf.length)
       throw new IllegalArgumentException("Could not scale down to desired image dimensions");
-    return scaledHeight;
+
+    return sf[i];
   }
 
   /**
-   * Decompress the JPEG source image or decode the YUV source image associated
-   * with this decompressor instance and output a grayscale, RGB, or CMYK image
-   * to the given destination buffer.
+   * Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+   * source image associated with this decompressor instance and output an
+   * 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+   * destination buffer.
    * <p>
-   * NOTE: The output image is fully recoverable if this method throws a
-   * non-fatal {@link TJException} (unless
-   * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
-   *
-   * @param dstBuf buffer that will receive the decompressed/decoded image.
-   * If the source image is a JPEG image, then this buffer should normally be
-   * <code>pitch * scaledHeight</code> bytes in size, where
-   * <code>scaledHeight</code> can be determined by calling <code>
-   * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
-   * </code> with one of the scaling factors returned from {@link
-   * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  If the
-   * source image is a YUV image, then this buffer should normally be
-   * <code>pitch * height</code> bytes in size, where <code>height</code> is
-   * the height of the YUV image.  However, the buffer may also be larger than
-   * the dimensions of the source image, in which case the <code>x</code>,
-   * <code>y</code>, and <code>pitch</code> parameters can be used to specify
-   * the region into which the source image should be decompressed/decoded.
+   * NOTE: The destination image is fully recoverable if this method throws a
+   * non-fatal {@link TJException} (unless {@link TJ#PARAM_STOPONWARNING} is
+   * set.)
+   *
+   * @param dstBuf buffer that will receive the packed-pixel
+   * decompressed/decoded image.  This buffer should normally be
+   * <code>pitch * destinationHeight</code> bytes in size.  However, the buffer
+   * may also be larger, in which case the <code>x</code>, <code>y</code>, and
+   * <code>pitch</code> parameters can be used to specify the region into which
+   * the source image should be decompressed/decoded.  NOTE: If the source
+   * image is a lossy JPEG image, then <code>destinationHeight</code> is either
+   * the scaled JPEG height (see {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()}, and
+   * {@link #getHeight}) or the height of the cropping region (see
+   * {@link #setCroppingRegion setCroppingRegion()}.)  If the source image is a
+   * YUV image or a lossless JPEG image, then <code>destinationHeight</code> is
+   * the height of the source image.
    *
    * @param x x offset (in pixels) of the region in the destination image into
    * which the source image should be decompressed/decoded
@@ -344,320 +405,456 @@ public class TJDecompressor implements Closeable {
    * @param y y offset (in pixels) of the region in the destination image into
    * which the source image should be decompressed/decoded
    *
-   * @param desiredWidth If the source image is a JPEG image, then this
-   * specifies the desired width (in pixels) of the decompressed image (or
-   * image region.)  If the desired destination image dimensions are different
-   * than the source image dimensions, then TurboJPEG will use scaling in the
-   * JPEG decompressor to generate the largest possible image that will fit
-   * within the desired dimensions.  Setting this to 0 is the same as setting
-   * it to the width of the JPEG image (in other words, the width will not be
-   * considered when determining the scaled image size.)  This parameter is
-   * ignored if the source image is a YUV image.
-   *
-   * @param pitch bytes per line of the destination image.  Normally, this
-   * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
-   * the destination image is unpadded, but you can use this to, for instance,
-   * pad each line of the destination image to a 4-byte boundary or to
-   * decompress/decode the source image into a region of a larger image.  NOTE:
-   * if the source image is a JPEG image, then <code>scaledWidth</code> can be
-   * determined by calling <code>
-   * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
-   * </code> or by calling {@link #getScaledWidth}.  If the source image is a
-   * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
-   * Setting this parameter to 0 is the equivalent of setting it to
-   * <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.
-   *
-   * @param desiredHeight If the source image is a JPEG image, then this
-   * specifies the desired height (in pixels) of the decompressed image (or
-   * image region.)  If the desired destination image dimensions are different
-   * than the source image dimensions, then TurboJPEG will use scaling in the
-   * JPEG decompressor to generate the largest possible image that will fit
-   * within the desired dimensions.  Setting this to 0 is the same as setting
-   * it to the height of the JPEG image (in other words, the height will not be
-   * considered when determining the scaled image size.)  This parameter is
-   * ignored if the source image is a YUV image.
+   * @param pitch bytes per row in the destination image.  Normally this should
+   * be set to <code>destinationWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>, if the
+   * destination image will be unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>destinationWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  However,
+   * you can also use this parameter to specify the row alignment/padding of
+   * the destination image, to skip rows, or to decompress/decode into a
+   * specific region of a larger image.  NOTE: if the source image is a lossy
+   * JPEG image, then <code>destinationWidth</code> is either the scaled JPEG
+   * width (see {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()}, and
+   * {@link #getWidth}) or the width of the cropping region (see
+   * {@link #setCroppingRegion setCroppingRegion()}.)  If the source image is a
+   * YUV image or a lossless JPEG image, then <code>destinationWidth</code> is
+   * the width of the source image.
    *
    * @param pixelFormat pixel format of the decompressed/decoded image (one of
    * {@link TJ#PF_RGB TJ.PF_*})
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
+  public void decompress8(byte[] dstBuf, int x, int y, int pitch,
+                          int pixelFormat) throws TJException {
+    if (jpegBuf == null && yuvImage == null)
+      throw new IllegalStateException("No source image is associated with this instance");
+    if (dstBuf == null || x < 0 || y < 0 || pitch < 0 || pixelFormat < 0 ||
+        pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress8()");
+    if (yuvImage != null) {
+      checkSubsampling();
+      decodeYUV8(yuvImage.getPlanes(), yuvImage.getOffsets(),
+                 yuvImage.getStrides(), dstBuf, x, y, yuvImage.getWidth(),
+                 pitch, yuvImage.getHeight(), pixelFormat);
+    } else
+      decompress8(jpegBuf, jpegBufSize, dstBuf, x, y, pitch, pixelFormat);
+  }
+
+  /**
+   * @deprecated Use {@link #set set()},
+   * {@link #setScalingFactor setScalingFactor()}, and
+   * {@link #decompress8(byte[], int, int, int, int)} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
                          int pitch, int desiredHeight, int pixelFormat,
                          int flags) throws TJException {
-    if (jpegBuf == null && yuvImage == null)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (dstBuf == null || x < 0 || y < 0 || pitch < 0 ||
-        (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
-        pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
+    if ((yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
+        flags < 0)
       throw new IllegalArgumentException("Invalid argument in decompress()");
-    if (yuvImage != null)
-      decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
-                yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
-                yuvImage.getWidth(), pitch, yuvImage.getHeight(), pixelFormat,
-                flags);
-    else {
-      if (x > 0 || y > 0)
-        decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
-                   desiredHeight, pixelFormat, flags);
-      else
-        decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
-                   desiredHeight, pixelFormat, flags);
+
+    if (yuvImage == null) {
+      TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+      setScalingFactor(sf);
     }
+    processFlags(flags);
+    decompress8(dstBuf, x, y, pitch, pixelFormat);
   }
 
   /**
-   * @deprecated Use
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
+   * Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+   * source image associated with this decompressor instance and return a
+   * buffer containing an 8-bit-per-sample packed-pixel decompressed image.
+   *
+   * @param pitch see
+   * {@link #decompress8(byte[], int, int, int, int)} for description
+   *
+   * @param pixelFormat pixel format of the decompressed image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
+   *
+   * @return a buffer containing an 8-bit-per-sample packed-pixel decompressed
+   * image.
+   */
+  public byte[] decompress8(int pitch, int pixelFormat) throws TJException {
+    if (pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress8()");
+    int pixelSize = TJ.getPixelSize(pixelFormat);
+    int scaledWidth = scalingFactor.getScaled(getJPEGWidth());
+    int scaledHeight = scalingFactor.getScaled(getJPEGHeight());
+    if (pitch == 0)
+      pitch = scaledWidth * pixelSize;
+    byte[] buf = new byte[pitch * scaledHeight];
+    decompress8(buf, 0, 0, pitch, pixelFormat);
+    return buf;
+  }
+
+  /**
+   * @deprecated Use {@link #set set()},
+   * {@link #setScalingFactor setScalingFactor()}, and
+   * {@link #decompress8(int, int)} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
-                         int desiredHeight, int pixelFormat, int flags)
-                         throws TJException {
-    decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
-               flags);
+  public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
+                           int pixelFormat, int flags) throws TJException {
+    if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
+        flags < 0)
+      throw new IllegalArgumentException("Invalid argument in decompress()");
+
+    if (yuvImage == null) {
+      TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+      setScalingFactor(sf);
+    }
+    processFlags(flags);
+    return decompress8(pitch, pixelFormat);
   }
 
   /**
-   * Decompress the JPEG source image associated with this decompressor
-   * instance and return a buffer containing the decompressed image.
+   * Decompress the 12-bit-per-sample JPEG source image associated with this
+   * decompressor instance and output a 12-bit-per-sample packed-pixel
+   * grayscale, RGB, or CMYK image to the given destination buffer.
+   * <p>
+   * NOTE: The destination image is fully recoverable if this method throws a
+   * non-fatal {@link TJException} (unless {@link TJ#PARAM_STOPONWARNING} is
+   * set.)
    *
-   * @param desiredWidth see
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)}
-   * for description
+   * @param dstBuf buffer that will receive the packed-pixel
+   * decompressed image.  This buffer should normally be
+   * <code>pitch * destinationHeight</code> samples in size.  However, the
+   * buffer may also be larger, in which case the <code>x</code>,
+   * <code>y</code>, and <code>pitch</code> parameters can be used to specify
+   * the region into which the source image should be decompressed.  NOTE: If
+   * the source image is a lossy JPEG image, then
+   * <code>destinationHeight</code> is either the scaled JPEG height (see
+   * {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()}, and
+   * {@link #getHeight}) or the height of the cropping region (see
+   * {@link #setCroppingRegion setCroppingRegion()}.)  If the source image is a
+   * lossless JPEG image, then <code>destinationHeight</code> is the height of
+   * the source image.
+   *
+   * @param x x offset (in pixels) of the region in the destination image into
+   * which the source image should be decompressed
+   *
+   * @param y y offset (in pixels) of the region in the destination image into
+   * which the source image should be decompressed
+   *
+   * @param pitch samples per row in the destination image.  Normally this
+   * should be set to <code>destinationWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>, if the
+   * destination image will be unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>destinationWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  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 image.  NOTE: if the source image is a lossy JPEG
+   * image, then <code>destinationWidth</code> is either the scaled JPEG width
+   * (see {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()}, and
+   * {@link #getWidth}) or the width of the cropping region (see
+   * {@link #setCroppingRegion setCroppingRegion()}.)  If the source image is a
+   * YUV image or a lossless JPEG image, then <code>destinationWidth</code> is
+   * the width of the source image.
+   *
+   * @param pixelFormat pixel format of the decompressed image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
+   */
+  public void decompress12(short[] dstBuf, int x, int y, int pitch,
+                           int pixelFormat) throws TJException {
+    if (jpegBuf == null)
+      throw new IllegalStateException(NO_ASSOC_ERROR);
+    if (dstBuf == null || x < 0 || y < 0 || pitch < 0 || pixelFormat < 0 ||
+        pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress12()");
+    decompress12(jpegBuf, jpegBufSize, dstBuf, x, y, pitch, pixelFormat);
+  }
+
+  /**
+   * Decompress the 12-bit-per-sample JPEG source image associated with this
+   * decompressor instance and return a buffer containing a 12-bit-per-sample
+   * packed-pixel decompressed image.
    *
    * @param pitch see
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)}
-   * for description
+   * {@link #decompress12(short[], int, int, int, int)} for description
    *
-   * @param desiredHeight see
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)}
-   * for description
+   * @param pixelFormat pixel format of the decompressed image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
+   *
+   * @return a buffer containing an 8-bit-per-sample packed-pixel decompressed
+   * image.
+   */
+  public short[] decompress12(int pitch, int pixelFormat) throws TJException {
+    if (pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress12()");
+    int pixelSize = TJ.getPixelSize(pixelFormat);
+    int scaledWidth = scalingFactor.getScaled(getJPEGWidth());
+    int scaledHeight = scalingFactor.getScaled(getJPEGHeight());
+    if (pitch == 0)
+      pitch = scaledWidth * pixelSize;
+    short[] buf = new short[pitch * scaledHeight];
+    decompress12(buf, 0, 0, pitch, pixelFormat);
+    return buf;
+  }
+
+  /**
+   * Decompress the 16-bit-per-sample lossless JPEG source image associated
+   * with this decompressor instance and output a 16-bit-per-sample
+   * packed-pixel grayscale, RGB, or CMYK image to the given destination
+   * buffer.
+   * <p>
+   * NOTE: The destination image is fully recoverable if this method throws a
+   * non-fatal {@link TJException} (unless {@link TJ#PARAM_STOPONWARNING} is
+   * set.)
+   *
+   * @param dstBuf buffer that will receive the packed-pixel
+   * decompressed image.  This buffer should normally be
+   * <code>pitch * jpegHeight</code> samples in size.  However, the buffer may
+   * also be larger, in which case the <code>x</code>,
+   * <code>y</code>, and <code>pitch</code> parameters can be used to specify
+   * the region into which the source image should be decompressed.
+   *
+   * @param x x offset (in pixels) of the region in the destination image into
+   * which the source image should be decompressed
+   *
+   * @param y y offset (in pixels) of the region in the destination image into
+   * which the source image should be decompressed
+   *
+   * @param pitch samples per row in the destination image.  Normally this
+   * should be set to <code>jpegWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>, if the
+   * destination image will be unpadded.  (Setting this parameter to 0 is the
+   * equivalent of setting it to <code>jpegWidth *
+   * {@link TJ#getPixelSize TJ.getPixelSize}(pixelFormat)</code>.)  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 image.
    *
    * @param pixelFormat pixel format of the decompressed image (one of
    * {@link TJ#PF_RGB TJ.PF_*})
+   */
+  public void decompress16(short[] dstBuf, int x, int y, int pitch,
+                           int pixelFormat) throws TJException {
+    if (jpegBuf == null)
+      throw new IllegalStateException(NO_ASSOC_ERROR);
+    if (dstBuf == null || x < 0 || y < 0 || pitch < 0 || pixelFormat < 0 ||
+        pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress16()");
+    decompress16(jpegBuf, jpegBufSize, dstBuf, x, y, pitch, pixelFormat);
+  }
+
+  /**
+   * Decompress the 16-bit-per-sample JPEG source image associated with this
+   * decompressor instance and return a buffer containing a 16-bit-per-sample
+   * packed-pixel decompressed image.
    *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * @param pitch see
+   * {@link #decompress16(short[], int, int, int, int)} for description
    *
-   * @return a buffer containing the decompressed image.
+   * @param pixelFormat pixel format of the decompressed image (one of
+   * {@link TJ#PF_RGB TJ.PF_*})
+   *
+   * @return a buffer containing an 8-bit-per-sample packed-pixel decompressed
+   * image.
    */
-  public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
-                           int pixelFormat, int flags) throws TJException {
-    if (pitch < 0 ||
-        (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
-        pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
-      throw new IllegalArgumentException("Invalid argument in decompress()");
+  public short[] decompress16(int pitch, int pixelFormat) throws TJException {
+    if (pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress16()");
     int pixelSize = TJ.getPixelSize(pixelFormat);
-    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
-    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
+    int scaledWidth = scalingFactor.getScaled(getJPEGWidth());
+    int scaledHeight = scalingFactor.getScaled(getJPEGHeight());
     if (pitch == 0)
       pitch = scaledWidth * pixelSize;
-    byte[] buf = new byte[pitch * scaledHeight];
-    decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
+    short[] buf = new short[pitch * scaledHeight];
+    decompress16(buf, 0, 0, pitch, pixelFormat);
     return buf;
   }
 
   /**
-   * Decompress the JPEG source image associated with this decompressor
-   * instance into a YUV planar image and store it in the given
-   * <code>YUVImage</code> instance.  This method performs JPEG decompression
-   * but leaves out the color conversion step, so a planar YUV image is
-   * generated instead of an RGB or grayscale image.  This method cannot be
+   * Decompress the 8-bit-per-sample JPEG source image associated with this
+   * decompressor instance into an 8-bit-per-sample planar YUV image and store
+   * it in the given {@link YUVImage} instance.  This method performs JPEG
+   * decompression but leaves out the color conversion step, so a planar YUV
+   * image is generated instead of a packed-pixel image.  This method cannot be
    * used to decompress JPEG source images with the CMYK or YCCK colorspace.
    * <p>
-   * NOTE: The YUV planar output image is fully recoverable if this method
+   * NOTE: The planar YUV destination image is fully recoverable if this method
    * throws a non-fatal {@link TJException} (unless
-   * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
+   * {@link TJ#PARAM_STOPONWARNING} is set.)
    *
-   * @param dstImage {@link YUVImage} instance that will receive the YUV planar
-   * image.  The level of subsampling specified in this <code>YUVImage</code>
-   * instance must match that of the JPEG image, and the width and height
-   * specified in the <code>YUVImage</code> instance must match one of the
-   * scaled image sizes that TurboJPEG is capable of generating from the JPEG
-   * source image.
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * @param dstImage {@link YUVImage} instance that will receive the planar YUV
+   * decompressed image.  The level of subsampling specified in this
+   * {@link YUVImage} instance must match that of the JPEG image, and the width
+   * and height specified in the {@link YUVImage} instance must match the
+   * scaled JPEG width and height (see {@link #setScalingFactor
+   * setScalingFactor()}, {@link TJScalingFactor#getScaled
+   * TJScalingFactor.getScaled()}, {@link #getWidth}, and {@link #getHeight}.)
    */
-  public void decompressToYUV(YUVImage dstImage, int flags)
-                              throws TJException {
+  public void decompressToYUV(YUVImage dstImage) throws TJException {
     if (jpegBuf == null)
       throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (dstImage == null || flags < 0)
+    if (dstImage == null)
       throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
-    int scaledWidth = getScaledWidth(dstImage.getWidth(),
-                                     dstImage.getHeight());
-    int scaledHeight = getScaledHeight(dstImage.getWidth(),
-                                       dstImage.getHeight());
-    if (scaledWidth != dstImage.getWidth() ||
-        scaledHeight != dstImage.getHeight())
-      throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
-    if (jpegSubsamp != dstImage.getSubsamp())
+    checkSubsampling();
+    if (get(TJ.PARAM_SUBSAMP) != dstImage.getSubsamp())
       throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
+    if (scalingFactor.getScaled(getJPEGWidth()) != dstImage.getWidth() ||
+        scalingFactor.getScaled(getJPEGHeight()) != dstImage.getHeight())
+      throw new IllegalArgumentException("YUVImage dimensions do not match the scaled JPEG dimensions");
 
-    decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
-                    dstImage.getOffsets(), dstImage.getWidth(),
-                    dstImage.getStrides(), dstImage.getHeight(), flags);
+    decompressToYUV8(jpegBuf, jpegBufSize, dstImage.getPlanes(),
+                     dstImage.getOffsets(), dstImage.getStrides());
   }
 
   /**
-   * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompressToYUV(YUVImage)} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
-    YUVImage dstYUVImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
-                                        jpegSubsamp);
-    decompressToYUV(dstYUVImage, flags);
+  public void decompressToYUV(YUVImage dstImage, int flags)
+                              throws TJException {
+    if (flags < 0)
+      throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
+
+    TJScalingFactor sf = getScalingFactor(dstImage.getWidth(),
+                                          dstImage.getHeight());
+    if (sf.getScaled(getJPEGWidth()) != dstImage.getWidth() ||
+        sf.getScaled(getJPEGHeight()) != dstImage.getHeight())
+      throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that the decompressor is capable of generating.");
+
+    setScalingFactor(sf);
+    processFlags(flags);
+    decompressToYUV(dstImage);
   }
 
   /**
-   * Decompress the JPEG source image associated with this decompressor
-   * instance into a set of Y, U (Cb), and V (Cr) image planes and return a
-   * <code>YUVImage</code> instance containing the decompressed image planes.
-   * This method performs JPEG decompression but leaves out the color
-   * conversion step, so a planar YUV image is generated instead of an RGB or
-   * grayscale image.  This method cannot be used to decompress JPEG source
-   * images with the CMYK or YCCK colorspace.
-   *
-   * @param desiredWidth desired width (in pixels) of the YUV image.  If the
-   * desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
-   * the width of the JPEG image (in other words, the width will not be
-   * considered when determining the scaled image size.)
+   * Decompress the 8-bit-per-sample JPEG source image associated with this
+   * decompressor instance into a set of 8-bit-per-sample Y, U (Cb), and V (Cr)
+   * image planes and return a {@link YUVImage} instance containing the
+   * decompressed image planes.  This method performs JPEG decompression but
+   * leaves out the color conversion step, so a planar YUV image is generated
+   * instead of a packed-pixel image.  This method cannot be used to decompress
+   * JPEG source images with the CMYK or YCCK colorspace.
    *
    * @param strides an array of integers, each specifying the number of bytes
-   * per line in the corresponding plane of the output image.  Setting the
-   * stride for any plane to 0 is the same as setting it to the scaled
-   * component width of the plane.  If <tt>strides</tt> is NULL, then the
-   * strides for all planes will be set to their respective scaled component
-   * widths.  You can adjust the strides in order to add an arbitrary amount of
-   * line padding to each plane.
-   *
-   * @param desiredHeight desired height (in pixels) of the YUV image.  If the
-   * desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
-   * the height of the JPEG image (in other words, the height will not be
-   * considered when determining the scaled image size.)
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
-   *
-   * @return a YUV planar image.
+   * 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 {@link YUVImage}.)  If <code>strides</code> 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.
+   *
+   * @return a {@link YUVImage} instance containing the decompressed image
+   * planes
    */
+  public YUVImage decompressToYUV(int[] strides) throws TJException {
+    int jpegWidth = getJPEGWidth();
+    int jpegHeight = getJPEGHeight();
+    checkSubsampling();
+    if (yuvImage != null)
+      throw new IllegalStateException("Source image is the wrong type");
+
+    YUVImage dstYUVImage = new YUVImage(scalingFactor.getScaled(jpegWidth),
+                                        null,
+                                        scalingFactor.getScaled(jpegHeight),
+                                        get(TJ.PARAM_SUBSAMP));
+    decompressToYUV(dstYUVImage);
+    return dstYUVImage;
+  }
+
+  /**
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompressToYUV(int[])} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public YUVImage decompressToYUV(int desiredWidth, int[] strides,
                                   int desiredHeight,
                                   int flags) throws TJException {
     if (flags < 0)
       throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
-    if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (jpegSubsamp >= TJ.NUMSAMP)
-      throw new IllegalStateException("JPEG header information is invalid");
-    if (yuvImage != null)
-      throw new IllegalStateException("Source image is the wrong type");
 
-    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
-    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
-    YUVImage dstYUVImage = new YUVImage(scaledWidth, null, scaledHeight,
-                                        jpegSubsamp);
-    decompressToYUV(dstYUVImage, flags);
-    return dstYUVImage;
+    TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+    setScalingFactor(sf);
+    processFlags(flags);
+    return decompressToYUV(strides);
   }
 
   /**
-   * Decompress the JPEG source image associated with this decompressor
-   * instance into a unified YUV planar image buffer and return a
-   * <code>YUVImage</code> instance containing the decompressed image.  This
-   * method performs JPEG decompression but leaves out the color conversion
-   * step, so a planar YUV image is generated instead of an RGB or grayscale
-   * image.  This method cannot be used to decompress JPEG source images with
-   * the CMYK or YCCK colorspace.
-   *
-   * @param desiredWidth desired width (in pixels) of the YUV image.  If the
-   * desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
-   * the width of the JPEG image (in other words, the width will not be
-   * considered when determining the scaled image size.)
-   *
-   * @param pad the width of each line in each plane of the YUV image will be
-   * padded to the nearest multiple of this number of bytes (must be a power of
-   * 2.)
-   *
-   * @param desiredHeight desired height (in pixels) of the YUV image.  If the
-   * desired image dimensions are different than the dimensions 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 dimensions.  Setting this to 0 is the same as setting it to
-   * the height of the JPEG image (in other words, the height will not be
-   * considered when determining the scaled image size.)
+   * Decompress the 8-bit-per-sample JPEG source image associated with this
+   * decompressor instance into an 8-bit-per-sample unified planar YUV image
+   * and return a {@link YUVImage} instance containing the decompressed image.
+   * This method performs JPEG decompression but leaves out the color
+   * conversion step, so a planar YUV image is generated instead of a
+   * packed-pixel image.  This method cannot be used to decompress JPEG source
+   * images with the CMYK or YCCK colorspace.
    *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * @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.)
    *
-   * @return a YUV planar image.
+   * @return a {@link YUVImage} instance containing the unified planar YUV
+   * decompressed image
    */
-  public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
-                                  int flags) throws TJException {
-    if (flags < 0)
-      throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
-    if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (jpegSubsamp >= TJ.NUMSAMP)
-      throw new IllegalStateException("JPEG header information is invalid");
+  public YUVImage decompressToYUV(int align) throws TJException {
+    int jpegWidth = getJPEGWidth();
+    int jpegHeight = getJPEGHeight();
+    checkSubsampling();
     if (yuvImage != null)
       throw new IllegalStateException("Source image is the wrong type");
 
-    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
-    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
-    YUVImage dstYUVImage = new YUVImage(scaledWidth, pad, scaledHeight,
-                                        jpegSubsamp);
-    decompressToYUV(dstYUVImage, flags);
+    YUVImage dstYUVImage = new YUVImage(scalingFactor.getScaled(jpegWidth),
+                                        align,
+                                        scalingFactor.getScaled(jpegHeight),
+                                        get(TJ.PARAM_SUBSAMP));
+    decompressToYUV(dstYUVImage);
     return dstYUVImage;
   }
 
   /**
-   * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompressToYUV(int)} instead.
    */
   @SuppressWarnings("checkstyle:JavadocMethod")
   @Deprecated
-  public byte[] decompressToYUV(int flags) throws TJException {
-    YUVImage dstYUVImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
-    decompressToYUV(dstYUVImage, flags);
-    return dstYUVImage.getBuf();
+  public YUVImage decompressToYUV(int desiredWidth, int align,
+                                  int desiredHeight, int flags)
+                                  throws TJException {
+    if (flags < 0)
+      throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
+
+    TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+    setScalingFactor(sf);
+    processFlags(flags);
+    return decompressToYUV(align);
   }
 
   /**
-   * Decompress the JPEG source image or decode the YUV source image associated
-   * with this decompressor instance and output a grayscale, RGB, or CMYK image
-   * to the given destination buffer.
+   * Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+   * source image associated with this decompressor instance and output an
+   * 8-bit-per-sample packed-pixel grayscale, RGB, or CMYK image to the given
+   * destination buffer.
    * <p>
-   * NOTE: The output image is fully recoverable if this method throws a
-   * non-fatal {@link TJException} (unless
-   * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
-   *
-   * @param dstBuf buffer that will receive the decompressed/decoded image.
-   * If the source image is a JPEG image, then this buffer should normally be
-   * <code>stride * scaledHeight</code> pixels in size, where
-   * <code>scaledHeight</code> can be determined by calling <code>
-   * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
-   * </code> with one of the scaling factors returned from {@link
-   * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  If the
-   * source image is a YUV image, then this buffer should normally be
-   * <code>stride * height</code> pixels in size, where <code>height</code> is
-   * the height of the YUV image.  However, the buffer may also be larger than
-   * the dimensions of the JPEG image, in which case the <code>x</code>,
-   * <code>y</code>, and <code>stride</code> parameters can be used to specify
-   * the region into which the source image should be decompressed.
+   * NOTE: The destination image is fully recoverable if this method throws a
+   * non-fatal {@link TJException} (unless {@link TJ#PARAM_STOPONWARNING}
+   * is set.)
+   *
+   * @param dstBuf buffer that will receive the packed-pixel
+   * decompressed/decoded image.  This buffer should normally be
+   * <code>stride * destinationHeight</code> pixels in size.  However, the
+   * buffer may also be larger, in which case the <code>x</code>,
+   * <code>y</code>, and <code>pitch</code> parameters can be used to specify
+   * the region into which the source image should be decompressed/decoded.
+   * NOTE: If the source image is a lossy JPEG image, then
+   * <code>destinationHeight</code> is either the scaled JPEG height (see
+   * {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()}, and
+   * {@link #getHeight}) or the height of the cropping region (see
+   * {@link #setCroppingRegion setCroppingRegion()}.)  If the source image is a
+   * YUV image or a lossless JPEG image, then <code>destinationHeight</code> is
+   * the height of the source image.
    *
    * @param x x offset (in pixels) of the region in the destination image into
    * which the source image should be decompressed/decoded
@@ -665,101 +862,94 @@ public class TJDecompressor implements Closeable {
    * @param y y offset (in pixels) of the region in the destination image into
    * which the source image should be decompressed/decoded
    *
-   * @param desiredWidth If the source image is a JPEG image, then this
-   * specifies the desired width (in pixels) of the decompressed image (or
-   * image region.)  If the desired destination image dimensions are different
-   * than the source image dimensions, then TurboJPEG will use scaling in the
-   * JPEG decompressor to generate the largest possible image that will fit
-   * within the desired dimensions.  Setting this to 0 is the same as setting
-   * it to the width of the JPEG image (in other words, the width will not be
-   * considered when determining the scaled image size.)  This parameter is
-   * ignored if the source image is a YUV image.
-   *
-   * @param stride pixels per line of the destination image.  Normally, this
-   * should be set to <code>scaledWidth</code>, but you can use this to, for
-   * instance, decompress the JPEG image into a region of a larger image.
-   * NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
-   * can be determined by calling <code>
-   * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
-   * </code> or by calling {@link #getScaledWidth}.  If the source image is a
-   * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
-   * Setting this parameter to 0 is the equivalent of setting it to
-   * <code>scaledWidth</code>.
-   *
-   * @param desiredHeight If the source image is a JPEG image, then this
-   * specifies the desired height (in pixels) of the decompressed image (or
-   * image region.)  If the desired destination image dimensions are different
-   * than the source image dimensions, then TurboJPEG will use scaling in the
-   * JPEG decompressor to generate the largest possible image that will fit
-   * within the desired dimensions.  Setting this to 0 is the same as setting
-   * it to the height of the JPEG image (in other words, the height will not be
-   * considered when determining the scaled image size.)  This parameter is
-   * ignored if the source image is a YUV image.
+   * @param stride pixels per row in the destination image.  Normally this
+   * should be set to <code>destinationWidth</code>.  (Setting this parameter
+   * to 0 is the equivalent of setting it to <code>destinationWidth</code>.)
+   * However, you can also use this parameter to skip rows or to
+   * decompress/decode into a specific region of a larger image.  NOTE: if the
+   * source image is a lossy JPEG image, then <code>destinationWidth</code> is
+   * either the scaled JPEG width (see {@link #setScalingFactor
+   * setScalingFactor()}, {@link TJScalingFactor#getScaled
+   * TJScalingFactor.getScaled()}, and {@link #getWidth}) or the width of the
+   * cropping region (see {@link #setCroppingRegion setCroppingRegion()}.)  If
+   * the source image is a YUV image or a lossless JPEG image, then
+   * <code>destinationWidth</code> is the width of the source image.
    *
-   * @param pixelFormat pixel format of the decompressed image (one of
+   * @param pixelFormat pixel format of the decompressed/decoded image (one of
    * {@link TJ#PF_RGB TJ.PF_*})
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
+  public void decompress8(int[] dstBuf, int x, int y, int stride,
+                          int pixelFormat) throws TJException {
+    if (jpegBuf == null && yuvImage == null)
+      throw new IllegalStateException("No source image is associated with this instance");
+    if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
+        pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+      throw new IllegalArgumentException("Invalid argument in decompress8()");
+    if (yuvImage != null) {
+      checkSubsampling();
+      decodeYUV8(yuvImage.getPlanes(), yuvImage.getOffsets(),
+                 yuvImage.getStrides(), dstBuf, x, y, yuvImage.getWidth(),
+                 stride, yuvImage.getHeight(), pixelFormat);
+    } else
+      decompress8(jpegBuf, jpegBufSize, dstBuf, x, y, stride, pixelFormat);
+  }
+
+  /**
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompress8(int[], int, int, int, int)}
+   * instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
                          int stride, int desiredHeight, int pixelFormat,
                          int flags) throws TJException {
-    if (jpegBuf == null && yuvImage == null)
-      throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
-        (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
-        pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
+    if ((yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
+       flags < 0)
       throw new IllegalArgumentException("Invalid argument in decompress()");
-    if (yuvImage != null)
-      decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
-                yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
-                yuvImage.getWidth(), stride, yuvImage.getHeight(), pixelFormat,
-                flags);
-    else
-      decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
-                 desiredHeight, pixelFormat, flags);
+
+    if (yuvImage == null) {
+      TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+      setScalingFactor(sf);
+    }
+    processFlags(flags);
+    decompress8(dstBuf, x, y, stride, pixelFormat);
   }
 
   /**
-   * Decompress the JPEG source image or decode the YUV source image associated
-   * with this decompressor instance and output a decompressed/decoded image to
-   * the given <code>BufferedImage</code> instance.
+   * Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+   * source image associated with this decompressor instance and output an
+   * 8-bit-per-sample packed-pixel decompressed/decoded image to the given
+   * <code>BufferedImage</code> instance.
    * <p>
-   * NOTE: The output image is fully recoverable if this method throws a
-   * non-fatal {@link TJException} (unless
-   * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.)
+   * NOTE: The destination image is fully recoverable if this method throws a
+   * non-fatal {@link TJException} (unless {@link TJ#PARAM_STOPONWARNING}
+   * is set.)
    *
    * @param dstImage a <code>BufferedImage</code> instance that will receive
-   * the decompressed/decoded image.  If the source image is a JPEG image, then
-   * the width and height of the <code>BufferedImage</code> instance must match
-   * one of the scaled image sizes that TurboJPEG is capable of generating from
-   * the JPEG image.  If the source image is a YUV image, then the width and
-   * height of the <code>BufferedImage</code> instance must match the width and
-   * height of the YUV image.
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * the packed-pixel decompressed/decoded image.  If the source image is a
+   * lossy JPEG image, then the width and height of the
+   * <code>BufferedImage</code> instance must match the scaled JPEG width and
+   * height (see {@link #setScalingFactor setScalingFactor()},
+   * {@link TJScalingFactor#getScaled TJScalingFactor.getScaled()},
+   * {@link #getWidth}, and {@link #getHeight}) or the width and height of the
+   * cropping region (see {@link #setCroppingRegion setCroppingRegion()}.)  If
+   * the source image is a YUV image or a lossless JPEG image, then the width
+   * and height of the <code>BufferedImage</code> instance must match the width
+   * and height of the source image.
    */
-  public void decompress(BufferedImage dstImage, int flags)
-                         throws TJException {
-    if (dstImage == null || flags < 0)
-      throw new IllegalArgumentException("Invalid argument in decompress()");
-    int desiredWidth = dstImage.getWidth();
-    int desiredHeight = dstImage.getHeight();
-    int scaledWidth, scaledHeight;
+  public void decompress8(BufferedImage dstImage) throws TJException {
+    if (dstImage == null)
+      throw new IllegalArgumentException("Invalid argument in decompress8()");
 
     if (yuvImage != null) {
-      if (desiredWidth != yuvImage.getWidth() ||
-          desiredHeight != yuvImage.getHeight())
+      if (dstImage.getWidth() != yuvImage.getWidth() ||
+          dstImage.getHeight() != yuvImage.getHeight())
         throw new IllegalArgumentException("BufferedImage dimensions do not match the dimensions of the source image.");
-      scaledWidth = yuvImage.getWidth();
-      scaledHeight = yuvImage.getHeight();
     } else {
-      scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
-      scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
-      if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
-        throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
+      if (scalingFactor.getScaled(getJPEGWidth()) != dstImage.getWidth() ||
+          scalingFactor.getScaled(getJPEGHeight()) != dstImage.getHeight())
+        throw new IllegalArgumentException("BufferedImage dimensions do not match the scaled JPEG dimensions.");
     }
     int pixelFormat;  boolean intPixels = false;
     if (byteOrder == null)
@@ -801,16 +991,15 @@ public class TJDecompressor implements Closeable {
       int stride = sm.getScanlineStride();
       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
       int[] buf = db.getData();
-      if (yuvImage != null)
-        decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
-                  yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
-                  yuvImage.getWidth(), stride, yuvImage.getHeight(),
-                  pixelFormat, flags);
-      else {
+      if (yuvImage != null) {
+        checkSubsampling();
+        decodeYUV8(yuvImage.getPlanes(), yuvImage.getOffsets(),
+                   yuvImage.getStrides(), buf, 0, 0, yuvImage.getWidth(),
+                   stride, yuvImage.getHeight(), pixelFormat);
+      else {
         if (jpegBuf == null)
           throw new IllegalStateException(NO_ASSOC_ERROR);
-        decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
-                   scaledHeight, pixelFormat, flags);
+        decompress8(jpegBuf, jpegBufSize, buf, 0, 0, stride, pixelFormat);
       }
     } else {
       ComponentSampleModel sm =
@@ -821,46 +1010,76 @@ public class TJDecompressor implements Closeable {
       int pitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       byte[] buf = db.getData();
-      decompress(buf, 0, 0, scaledWidth, pitch, scaledHeight, pixelFormat,
-                 flags);
+      decompress8(buf, 0, 0, pitch, pixelFormat);
     }
   }
 
   /**
-   * Decompress the JPEG source image or decode the YUV source image associated
-   * with this decompressor instance and return a <code>BufferedImage</code>
-   * instance containing the decompressed/decoded image.
-   *
-   * @param desiredWidth see
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
-   * description
-   *
-   * @param desiredHeight see
-   * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
-   * description
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompress8(BufferedImage)} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
+  public void decompress(BufferedImage dstImage, int flags)
+                         throws TJException {
+    if (flags < 0)
+      throw new IllegalArgumentException("Invalid argument in decompress()");
+
+    if (yuvImage == null) {
+      TJScalingFactor sf = getScalingFactor(dstImage.getWidth(),
+                                            dstImage.getHeight());
+      if (sf.getScaled(getJPEGWidth()) != dstImage.getWidth() ||
+          sf.getScaled(getJPEGHeight()) != dstImage.getHeight())
+        throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
+
+      setScalingFactor(sf);
+    }
+
+    processFlags(flags);
+    decompress8(dstImage);
+  }
+
+  /**
+   * Decompress the 8-bit-per-sample JPEG source image or decode the planar YUV
+   * source image associated with this decompressor instance and return a
+   * <code>BufferedImage</code> instance containing the 8-bit-per-sample
+   * packed-pixel decompressed/decoded image.
    *
    * @param bufferedImageType the image type of the <code>BufferedImage</code>
    * instance that will be created (for instance,
    * <code>BufferedImage.TYPE_INT_RGB</code>)
    *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
-   *
    * @return a <code>BufferedImage</code> instance containing the
-   * decompressed/decoded image.
+   * 8-bit-per-sample packed-pixel decompressed/decoded image.
    */
+  public BufferedImage decompress8(int bufferedImageType) throws TJException {
+    BufferedImage img =
+      new BufferedImage(scalingFactor.getScaled(getJPEGWidth()),
+                        scalingFactor.getScaled(getJPEGHeight()),
+                        bufferedImageType);
+    decompress8(img);
+    return img;
+  }
+
+  /**
+   * @deprecated Use {@link #set set()}, {@link #setScalingFactor
+   * setScalingFactor()}, and {@link #decompress8(int)} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public BufferedImage decompress(int desiredWidth, int desiredHeight,
                                   int bufferedImageType, int flags)
                                   throws TJException {
     if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
         flags < 0)
       throw new IllegalArgumentException("Invalid argument in decompress()");
-    int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
-    int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
-    BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
-                                          bufferedImageType);
-    decompress(img, flags);
-    return img;
+
+    if (yuvImage == null) {
+      TJScalingFactor sf = getScalingFactor(desiredWidth, desiredHeight);
+      setScalingFactor(sf);
+    }
+    processFlags(flags);
+    return decompress8(bufferedImageType);
   }
 
   /**
@@ -883,6 +1102,20 @@ public class TJDecompressor implements Closeable {
     }
   };
 
+  @SuppressWarnings("deprecation")
+  final void processFlags(int flags) {
+    set(TJ.PARAM_BOTTOMUP, (flags & TJ.FLAG_BOTTOMUP) != 0 ? 1 : 0);
+    set(TJ.PARAM_FASTUPSAMPLE, (flags & TJ.FLAG_FASTUPSAMPLE) != 0 ? 1 : 0);
+    set(TJ.PARAM_FASTDCT, (flags & TJ.FLAG_FASTDCT) != 0 ? 1 : 0);
+    set(TJ.PARAM_STOPONWARNING, (flags & TJ.FLAG_STOPONWARNING) != 0 ? 1 : 0);
+    set(TJ.PARAM_SCANLIMIT, (flags & TJ.FLAG_LIMITSCANS) != 0 ? 500 : 0);
+  }
+
+  final void checkSubsampling() {
+    if (get(TJ.PARAM_SUBSAMP) == TJ.SAMP_UNKNOWN)
+      throw new IllegalStateException("Unknown or unspecified subsampling level");
+  }
+
   private native void init() throws TJException;
 
   private native void destroy() throws TJException;
@@ -890,51 +1123,58 @@ public class TJDecompressor implements Closeable {
   private native void decompressHeader(byte[] srcBuf, int size)
     throws TJException;
 
-  @Deprecated
-  private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
-    int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
-    throws TJException;
+  private native void setCroppingRegion() throws TJException;
 
-  private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
-    int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
-    int flags) throws TJException;
+  @SuppressWarnings("checkstyle:HiddenField")
+  private native void decompress8(byte[] srcBuf, int size, byte[] dstBuf,
+    int x, int y, int pitch, int pixelFormat) throws TJException;
 
-  @Deprecated
-  private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
-    int desiredWidth, int stride, int desiredHeight, int pixelFormat,
-    int flags) throws TJException;
+  @SuppressWarnings("checkstyle:HiddenField")
+  private native void decompress12(byte[] srcBuf, int size, short[] dstBuf,
+    int x, int y, int pitch, int pixelFormat) throws TJException;
 
-  private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
-    int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
-    int flags) throws TJException;
+  @SuppressWarnings("checkstyle:HiddenField")
+  private native void decompress16(byte[] srcBuf, int size, short[] dstBuf,
+    int x, int y, int pitch, int pixelFormat) throws TJException;
 
-  @Deprecated
-  private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
-    int flags) throws TJException;
+  @SuppressWarnings("checkstyle:HiddenField")
+  private native void decompress8(byte[] srcBuf, int size, int[] dstBuf, int x,
+    int y, int stride, int pixelFormat) throws TJException;
+
+  @SuppressWarnings("checkstyle:HiddenField")
+  private native void decompressToYUV8(byte[] srcBuf, int size,
+    byte[][] dstPlanes, int[] dstOffsets, int[] dstStrides) throws TJException;
 
-  private native void decompressToYUV(byte[] srcBuf, int size,
-    byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
-    int desiredheight, int flags) throws TJException;
+  private native void decodeYUV8(byte[][] srcPlanes, int[] srcOffsets,
+    int[] srcStrides, byte[] dstBuf, int x, int y, int width, int pitch,
+    int height, int pixelFormat) throws TJException;
 
-  private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
-    int[] srcStrides, int subsamp, byte[] dstBuf, int x, int y, int width,
-    int pitch, int height, int pixelFormat, int flags) throws TJException;
+  private native void decodeYUV8(byte[][] srcPlanes, int[] srcOffsets,
+    int[] srcStrides, int[] dstBuf, int x, int y, int width, int stride,
+    int height, int pixelFormat) throws TJException;
 
-  private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
-    int[] srcStrides, int subsamp, int[] dstBuf, int x, int y, int width,
-    int stride, int height, int pixelFormat, int flags) throws TJException;
+  /**
+   * @hidden
+   * Ugly hack alert.  It isn't straightforward to save 12-bit-per-sample and
+   * 16-bit-per-sample images using the ImageIO and BufferedImage classes, and
+   * ImageIO doesn't support PBMPLUS files anyhow.  This method accesses
+   * tj3SaveImage() through JNI and copies the pixel data between the C and
+   * Java heaps.  Currently it is undocumented and used only by TJBench.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  public native void saveImage(int precision, String fileName, Object srcBuf,
+                               int width, int pitch, int height,
+                               int pixelFormat) throws TJException;
 
   static {
     TJLoader.load();
   }
 
-  protected long handle = 0;
-  protected byte[] jpegBuf = null;
-  protected int jpegBufSize = 0;
-  protected YUVImage yuvImage = null;
-  protected int jpegWidth = 0;
-  protected int jpegHeight = 0;
-  protected int jpegSubsamp = -1;
-  protected int jpegColorspace = -1;
+  private long handle = 0;
+  private byte[] jpegBuf = null;
+  private int jpegBufSize = 0;
+  private YUVImage yuvImage = null;
+  private TJScalingFactor scalingFactor = TJ.UNSCALED;
+  private Rectangle croppingRegion = TJ.UNCROPPED;
   private ByteOrder byteOrder = null;
 }
index 41c4b45..7c32cce 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C)2011, 2013, 2018 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011, 2013, 2018, 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:
@@ -95,29 +96,30 @@ public class TJTransform extends Rectangle {
    * TJTransformer.transform()} to throw an exception if the transform is not
    * perfect.  Lossless transforms operate on MCU blocks, whose size depends on
    * the level of chrominance subsampling used.  If the image's width or height
-   * is not evenly divisible by the MCU block size (see {@link TJ#getMCUWidth}
-   * and {@link TJ#getMCUHeight}), 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.
+   * is not evenly divisible by the MCU block size (see {@link TJ#getMCUWidth
+   * TJ.getMCUWidth()} and {@link TJ#getMCUHeight TJ.getMCUHeight()}), 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.
    */
-  public static final int OPT_PERFECT     = 1;
+  public static final int OPT_PERFECT     = (1 << 0);
   /**
    * This option will discard any partial MCU blocks that cannot be
    * transformed.
    */
-  public static final int OPT_TRIM        = 2;
+  public static final int OPT_TRIM        = (1 << 1);
   /**
    * This option will enable lossless cropping.
    */
-  public static final int OPT_CROP        = 4;
+  public static final int OPT_CROP        = (1 << 2);
   /**
-   * This option will discard the color data in the input image and produce
-   * a grayscale output image.
+   * This option will discard the color data in the source image and produce a
+   * grayscale destination image.
    */
-  public static final int OPT_GRAY        = 8;
+  public static final int OPT_GRAY        = (1 << 3);
   /**
    * This option will prevent {@link TJTransformer#transform
    * TJTransformer.transform()} from outputting a JPEG image for this
@@ -125,21 +127,36 @@ public class TJTransform extends Rectangle {
    * filter to capture the transformed DCT coefficients without transcoding
    * them.
    */
-  public static final int OPT_NOOUTPUT    = 16;
+  public static final int OPT_NOOUTPUT    = (1 << 4);
   /**
-   * This option will enable progressive entropy coding in the output image
+   * This option will enable progressive entropy coding in the JPEG image
    * generated by this particular transform.  Progressive entropy coding will
    * generally improve compression relative to baseline entropy coding (the
-   * default), but it will reduce compression and decompression performance
-   * considerably.
+   * default), but it will reduce decompression performance considerably.
+   * Can be combined with {@link #OPT_ARITHMETIC}.  Implies
+   * {@link #OPT_OPTIMIZE} unless {@link #OPT_ARITHMETIC} is also specified.
    */
-  public static final int OPT_PROGRESSIVE = 32;
+  public static final int OPT_PROGRESSIVE = (1 << 5);
   /**
    * This option will prevent {@link TJTransformer#transform
    * TJTransformer.transform()} from copying any extra markers (including EXIF
-   * and ICC profile data) from the source image to the output image.
+   * and ICC profile data) from the source image to the destination image.
    */
-  public static final int OPT_COPYNONE    = 64;
+  public static final int OPT_COPYNONE    = (1 << 6);
+  /**
+   * This option will enable arithmetic entropy coding in the JPEG image
+   * generated by this particular transform.  Arithmetic entropy coding will
+   * generally improve compression relative to Huffman entropy coding (the
+   * default), but it will reduce decompression performance considerably.  Can
+   * be combined with {@link #OPT_PROGRESSIVE}.
+   */
+  public static final int OPT_ARITHMETIC  = (1 << 7);
+  /**
+   * This option will enable optimized baseline entropy coding in the JPEG
+   * image generated by this particular transform.  Optimized baseline entropy
+   * coding will improve compression slightly (generally 5% or less.)
+   */
+  public static final int OPT_OPTIMIZE    = (1 << 8);
 
 
   /**
@@ -152,10 +169,12 @@ public class TJTransform extends Rectangle {
    * Create a new lossless transform instance with the given parameters.
    *
    * @param x the left boundary of the cropping region.  This must be evenly
-   * divisible by the MCU block width (see {@link TJ#getMCUWidth})
+   * divisible by the MCU block width (see {@link TJ#getMCUWidth
+   * TJ.getMCUWidth()})
    *
    * @param y the upper boundary of the cropping region.  This must be evenly
-   * divisible by the MCU block height (see {@link TJ#getMCUHeight})
+   * divisible by the MCU block height (see {@link TJ#getMCUHeight
+   * TJ.getMCUHeight()})
    *
    * @param w the width of the cropping region.  Setting this to 0 is the
    * equivalent of setting it to (width of the source JPEG image -
@@ -165,13 +184,13 @@ public class TJTransform extends Rectangle {
    * equivalent of setting it to (height of the source JPEG image -
    * <code>y</code>).
    *
-   * @param op one of the transform operations (<code>OP_*</code>)
+   * @param op one of the transform operations ({@link #OP_NONE OP_*})
    *
    * @param options the bitwise OR of one or more of the transform options
-   * (<code>OPT_*</code>)
+   * ({@link #OPT_PERFECT OPT_*})
    *
-   * @param cf an instance of an object that implements the {@link
-   * TJCustomFilter} interface, or null if no custom filter is needed
+   * @param cf an instance of an object that implements the
+   * {@link TJCustomFilter} interface, or null if no custom filter is needed
    */
   @SuppressWarnings("checkstyle:HiddenField")
   public TJTransform(int x, int y, int w, int h, int op, int options,
@@ -185,18 +204,18 @@ public class TJTransform extends Rectangle {
   /**
    * Create a new lossless transform instance with the given parameters.
    *
-   * @param r a <code>Rectangle</code> instance that specifies the cropping
-   * region.  See {@link
-   * #TJTransform(int, int, int, int, int, int, TJCustomFilter)} for more
-   * detail.
+   * @param r a <code>java.awt.Rectangle</code> instance that specifies the
+   * cropping region.  See
+   * {@link #TJTransform(int, int, int, int, int, int, TJCustomFilter)} for
+   * more details.
    *
-   * @param op one of the transform operations (<code>OP_*</code>)
+   * @param op one of the transform operations ({@link #OP_NONE OP_*})
    *
    * @param options the bitwise OR of one or more of the transform options
-   * (<code>OPT_*</code>)
+   * ({@link #OPT_PERFECT OPT_*})
    *
-   * @param cf an instance of an object that implements the {@link
-   * TJCustomFilter} interface, or null if no custom filter is needed
+   * @param cf an instance of an object that implements the
+   * {@link TJCustomFilter} interface, or null if no custom filter is needed
    */
   @SuppressWarnings("checkstyle:HiddenField")
   public TJTransform(Rectangle r, int op, int options,
@@ -208,13 +227,14 @@ public class TJTransform extends Rectangle {
   }
 
   /**
-   * Transform operation (one of <code>OP_*</code>)
+   * Transform operation (one of {@link #OP_NONE OP_*})
    */
   @SuppressWarnings("checkstyle:VisibilityModifier")
   public int op = 0;
 
   /**
-   * Transform options (bitwise OR of one or more of <code>OPT_*</code>)
+   * Transform options (bitwise OR of one or more of
+   * {@link #OPT_PERFECT OPT_*})
    */
   @SuppressWarnings("checkstyle:VisibilityModifier")
   public int options = 0;
index d7a56f3..4d46b5a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011, 2013-2015 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011, 2013-2015, 2023 D. R. Commander.  All Rights Reserved.
  * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,10 +43,12 @@ public class TJTransformer extends TJDecompressor {
 
   /**
    * Create a TurboJPEG lossless transformer instance and associate the JPEG
-   * image stored in <code>jpegImage</code> with the newly created instance.
+   * source image stored in <code>jpegImage</code> with the newly created
+   * instance.
    *
-   * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
-   * be the length of the array.)  This buffer is not modified.
+   * @param jpegImage buffer containing the JPEG source image to transform.
+   * (The size of the JPEG image is assumed to be the length of the array.)
+   * This buffer is not modified.
    */
   public TJTransformer(byte[] jpegImage) throws TJException {
     init();
@@ -55,12 +57,13 @@ public class TJTransformer extends TJDecompressor {
 
   /**
    * Create a TurboJPEG lossless transformer instance and associate the JPEG
-   * image of length <code>imageSize</code> bytes stored in
+   * source image of length <code>imageSize</code> bytes stored in
    * <code>jpegImage</code> with the newly created instance.
    *
-   * @param jpegImage JPEG image buffer.  This buffer is not modified.
+   * @param jpegImage buffer containing the JPEG source image to transform.
+   * This buffer is not modified.
    *
-   * @param imageSize size of the JPEG image (in bytes)
+   * @param imageSize size of the JPEG source image (in bytes)
    */
   public TJTransformer(byte[] jpegImage, int imageSize) throws TJException {
     init();
@@ -68,81 +71,99 @@ public class TJTransformer extends TJDecompressor {
   }
 
   /**
-   * Losslessly transform the JPEG image associated with this transformer
-   * instance into one or more JPEG images stored in the given destination
-   * buffers.  Lossless transforms work by moving the raw 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 method provides a means of
-   * generating multiple transformed images from the same source or of applying
-   * multiple transformations simultaneously, in order to eliminate the need to
-   * read the source coefficients multiple times.
+   * Losslessly transform the JPEG source image associated with this
+   * transformer instance into one or more JPEG images stored in the given
+   * destination buffers.  Lossless transforms work by moving the raw
+   * 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 method
+   * provides a means of generating multiple transformed images from the same
+   * source or of applying multiple transformations simultaneously, in order to
+   * eliminate the need to read the source coefficients multiple times.
    *
-   * @param dstBufs an array of image buffers.  <code>dstbufs[i]</code> will
-   * receive a JPEG image that has been transformed using the parameters in
-   * <code>transforms[i]</code>.  Use {@link TJ#bufSize} to determine the
-   * maximum size for each buffer based on the transformed or cropped width and
-   * height and the level of subsampling used in the source image.
+   * @param dstBufs an array of JPEG destination buffers.
+   * <code>dstbufs[i]</code> will receive a JPEG image that has been
+   * transformed using the parameters in <code>transforms[i]</code>.  Use
+   * {@link TJ#bufSize TJ.bufSize()} to determine the maximum size for each
+   * buffer based on the transformed or cropped width and height and the level
+   * of subsampling used in the source image.
    *
    * @param transforms an array of {@link TJTransform} instances, each of
    * which specifies the transform parameters and/or cropping region for the
-   * corresponding transformed output image
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * corresponding transformed JPEG image
+   */
+  public void transform(byte[][] dstBufs, TJTransform[] transforms)
+                        throws TJException {
+    transformedSizes = transform(getJPEGBuf(), getJPEGSize(), dstBufs,
+                                 transforms);
+  }
+
+  /**
+   * @deprecated Use {@link #set TJDecompressor.set()} and
+   * {@link #transform(byte[][], TJTransform[])} instead.
    */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
   public void transform(byte[][] dstBufs, TJTransform[] transforms,
                         int flags) throws TJException {
-    if (jpegBuf == null)
-      throw new IllegalStateException("JPEG buffer not initialized");
-    transformedSizes = transform(jpegBuf, jpegBufSize, dstBufs, transforms,
-                                 flags);
+    processFlags(flags);
+    transform(dstBufs, transforms);
   }
 
   /**
-   * Losslessly transform the JPEG image associated with this transformer
-   * instance and return an array of {@link TJDecompressor} instances, each of
-   * which has a transformed JPEG image associated with it.
+   * Losslessly transform the JPEG source image associated with this
+   * transformer instance and return an array of {@link TJDecompressor}
+   * instances, each of which has a transformed JPEG image associated with it.
    *
    * @param transforms an array of {@link TJTransform} instances, each of
    * which specifies the transform parameters and/or cropping region for the
-   * corresponding transformed output image
-   *
-   * @param flags the bitwise OR of one or more of
-   * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
+   * corresponding transformed JPEG image
    *
    * @return an array of {@link TJDecompressor} instances, each of
    * which has a transformed JPEG image associated with it.
    */
-  public TJDecompressor[] transform(TJTransform[] transforms, int flags)
+  public TJDecompressor[] transform(TJTransform[] transforms)
                                     throws TJException {
     byte[][] dstBufs = new byte[transforms.length][];
-    if (jpegWidth < 1 || jpegHeight < 1)
+    if (getWidth() < 1 || getHeight() < 1)
       throw new IllegalStateException("JPEG buffer not initialized");
+    checkSubsampling();
     for (int i = 0; i < transforms.length; i++) {
-      int w = jpegWidth, h = jpegHeight;
+      int w = getWidth(), h = getHeight();
       if ((transforms[i].options & TJTransform.OPT_CROP) != 0) {
         if (transforms[i].width != 0) w = transforms[i].width;
         if (transforms[i].height != 0) h = transforms[i].height;
       }
-      dstBufs[i] = new byte[TJ.bufSize(w, h, jpegSubsamp)];
+      dstBufs[i] = new byte[TJ.bufSize(w, h, get(TJ.PARAM_SUBSAMP))];
     }
     TJDecompressor[] tjd = new TJDecompressor[transforms.length];
-    transform(dstBufs, transforms, flags);
+    transform(dstBufs, transforms);
     for (int i = 0; i < transforms.length; i++)
       tjd[i] = new TJDecompressor(dstBufs[i], transformedSizes[i]);
     return tjd;
   }
 
   /**
+   * @deprecated Use {@link #set TJDecompressor.set()} and
+   * {@link #transform(TJTransform[])} instead.
+   */
+  @SuppressWarnings("checkstyle:JavadocMethod")
+  @Deprecated
+  public TJDecompressor[] transform(TJTransform[] transforms, int flags)
+                                    throws TJException {
+    processFlags(flags);
+    return transform(transforms);
+  }
+
+  /**
    * Returns an array containing the sizes of the transformed JPEG images
-   * generated by the most recent transform operation.
+   * (in bytes) generated by the most recent transform operation.
    *
    * @return an array containing the sizes of the transformed JPEG images
-   * generated by the most recent transform operation.
+   * (in bytes) generated by the most recent transform operation.
    */
   public int[] getTransformedSizes() {
     if (transformedSizes == null)
@@ -153,7 +174,7 @@ public class TJTransformer extends TJDecompressor {
   private native void init() throws TJException;
 
   private native int[] transform(byte[] srcBuf, int srcSize, byte[][] dstBufs,
-    TJTransform[] transforms, int flags) throws TJException;
+    TJTransform[] transforms) throws TJException;
 
   static {
     TJLoader.load();
index 4da9843..c2a43fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2014, 2017 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2014, 2017, 2023 D. R. Commander.  All Rights Reserved.
  * Copyright (C)2015 Viktor Szathmáry.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
 package org.libjpegturbo.turbojpeg;
 
 /**
- * This class encapsulates a YUV planar image and the metadata
+ * This class encapsulates a planar YUV image and the metadata
  * associated with it.  The TurboJPEG API allows both the JPEG compression and
  * decompression pipelines to be split into stages:  YUV encode, compress from
  * YUV, decompress to YUV, and YUV decode.  A <code>YUVImage</code> instance
@@ -38,30 +38,32 @@ package org.libjpegturbo.turbojpeg;
  * operations and as the source image for compress-from-YUV and YUV decode
  * operations.
  * <p>
- * Technically, the JPEG format uses the YCbCr colorspace (which technically is
- * not a "colorspace" but rather 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.
+ * 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.
  * <p>
  * 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 (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
- * 4:1:1, 1 in the case of 4:4:4 or grayscale.)  Similarly, the luminance plane
- * height is the image height padded to the nearest multiple of the vertical
- * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
- * or grayscale.)  The chrominance plane width is equal to the luminance plane
- * width divided by the horizontal subsampling factor, and the chrominance
- * plane height is equal to the luminance plane height divided by the vertical
- * subsampling factor.
+ * subsampling factor (1 in the case of 4:4:4, grayscale, 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 YUVImage methods.  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.
  * <p>
  * For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
  * used, then the luminance plane would be 36 x 35 bytes, and each of the
- * chrominance planes would be 18 x 35 bytes.  If you specify a line padding of
- * 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
- * each of the chrominance planes would be 20 x 35 bytes.
+ * chrominance planes would be 18 x 35 bytes.  If you specify a row alignment
+ * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes,
+ * and each of the chrominance planes would be 20 x 35 bytes.
  */
 public class YUVImage {
 
@@ -75,7 +77,7 @@ public class YUVImage {
    * @param width width (in pixels) of the YUV image
    *
    * @param strides an array of integers, each specifying the number of bytes
-   * per line in the corresponding plane of the YUV image.  Setting the stride
+   * 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
    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
    * strides for all planes will be set to their respective plane widths.  When
@@ -92,22 +94,24 @@ public class YUVImage {
   }
 
   /**
-   * Create a new <code>YUVImage</code> instance backed by a unified image
-   * buffer, and allocate memory for the image buffer.
+   * Create a new <code>YUVImage</code> instance backed by a unified buffer,
+   * and allocate memory for the buffer.
    *
    * @param width width (in pixels) of the YUV image
    *
-   * @param pad Each line of each plane in the YUV image buffer will be padded
-   * to this number of bytes (must be a power of 2.)
+   * @param align row alignment (in bytes) of the YUV image (must be a power of
+   * 2.)  Setting this parameter to n specifies that each row in each plane of
+   * the YUV image will be padded to the nearest multiple of n bytes
+   * (1 = unpadded.)
    *
    * @param height height (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling to be used in the YUV
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
-  public YUVImage(int width, int pad, int height, int subsamp) {
-    setBuf(new byte[TJ.bufSizeYUV(width, pad, height, subsamp)], width, pad,
-           height, subsamp);
+  public YUVImage(int width, int align, int height, int subsamp) {
+    setBuf(new byte[TJ.bufSizeYUV(width, align, height, subsamp)], width,
+           align, height, subsamp);
   }
 
   /**
@@ -130,11 +134,11 @@ public class YUVImage {
    * @param width width (in pixels) of the new YUV image (or subregion)
    *
    * @param strides an array of integers, each specifying the number of bytes
-   * per line in the corresponding plane of the YUV image.  Setting the stride
+   * 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
    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
    * strides for all planes will be set to their respective plane widths.  You
-   * can adjust the strides in order to add an arbitrary amount of line padding
+   * can adjust the strides in order to add an arbitrary amount of row padding
    * to each plane or to specify that this <code>YUVImage</code> instance is a
    * subregion of a larger image (in which case, <code>strides[i]</code> should
    * be set to the plane width of plane <code>i</code> in the larger image.)
@@ -150,29 +154,30 @@ public class YUVImage {
   }
 
   /**
-   * Create a new <code>YUVImage</code> instance from an existing unified image
+   * Create a new <code>YUVImage</code> instance from an existing unified
    * buffer.
    *
-   * @param yuvImage image buffer that contains or will contain YUV planar
-   * image data.  Use {@link TJ#bufSizeYUV} to determine the minimum size for
-   * this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
-   * sequentially in the buffer (see {@link YUVImage above} for a description
+   * @param yuvImage buffer that contains or will receive a unified planar YUV
+   * image.  Use {@link TJ#bufSizeYUV TJ.bufSizeYUV()} to determine the minimum
+   * size for this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
+   * sequentially in the buffer.  (See {@link YUVImage above} for a description
    * of the image format.)
    *
    * @param width width (in pixels) of the YUV image
    *
-   * @param pad the line padding used in the YUV image buffer.  For
-   * instance, if each line in each plane of the buffer is padded to the
-   * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
+   * @param align row alignment (in bytes) of the YUV image (must be a power of
+   * 2.)  Setting this parameter to n specifies that each row in each plane of
+   * the YUV image will be padded to the nearest multiple of n bytes
+   * (1 = unpadded.)
    *
    * @param height height (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling used in the YUV
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
-  public YUVImage(byte[] yuvImage, int width, int pad, int height,
+  public YUVImage(byte[] yuvImage, int width, int align, int height,
                   int subsamp) {
-    setBuf(yuvImage, width, pad, height, subsamp);
+    setBuf(yuvImage, width, align, height, subsamp);
   }
 
   /**
@@ -194,12 +199,12 @@ public class YUVImage {
    * @param width width (in pixels) of the YUV image (or subregion)
    *
    * @param strides an array of integers, each specifying the number of bytes
-   * per line in the corresponding plane of the YUV image.  Setting the stride
+   * 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
    * {@link YUVImage above}.)  If <code>strides</code> is null, then the
    * strides for all planes will be set to their respective plane widths.  You
-   * can adjust the strides in order to add an arbitrary amount of line padding
-   * to each plane or to specify that this <code>YUVImage</code> image is a
+   * can adjust the strides in order to add an arbitrary amount of row padding
+   * to each plane or to specify that this <code>YUVImage</code> instance is a
    * subregion of a larger image (in which case, <code>strides[i]</code> should
    * be set to the plane width of plane <code>i</code> in the larger image.)
    *
@@ -263,32 +268,34 @@ public class YUVImage {
   }
 
   /**
-   * Assign a unified image buffer to this <code>YUVImage</code> instance.
+   * Assign a unified buffer to this <code>YUVImage</code> instance.
    *
-   * @param yuvImage image buffer that contains or will contain YUV planar
-   * image data.  Use {@link TJ#bufSizeYUV} to determine the minimum size for
-   * this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
-   * sequentially in the buffer (see {@link YUVImage above} for a description
+   * @param yuvImage buffer that contains or will receive a unified planar YUV
+   * image.  Use {@link TJ#bufSizeYUV TJ.bufSizeYUV()} to determine the minimum
+   * size for this buffer.  The Y, U (Cb), and V (Cr) image planes are stored
+   * sequentially in the buffer.  (See {@link YUVImage above} for a description
    * of the image format.)
    *
    * @param width width (in pixels) of the YUV image
    *
-   * @param pad the line padding used in the YUV image buffer.  For
-   * instance, if each line in each plane of the buffer is padded to the
-   * nearest multiple of 4 bytes, then <code>pad</code> should be set to 4.
+   * @param align row alignment (in bytes) of the YUV image (must be a power of
+   * 2.)  Setting this parameter to n specifies that each row in each plane of
+   * the YUV image will be padded to the nearest multiple of n bytes
+   * (1 = unpadded.)
    *
    * @param height height (in pixels) of the YUV image
    *
    * @param subsamp the level of chrominance subsampling used in the YUV
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
-  public void setBuf(byte[] yuvImage, int width, int pad, int height,
+  public void setBuf(byte[] yuvImage, int width, int align, int height,
                      int subsamp) {
-    if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
-        height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
+    if (yuvImage == null || width < 1 || align < 1 ||
+        ((align & (align - 1)) != 0) || height < 1 || subsamp < 0 ||
+        subsamp >= TJ.NUMSAMP)
       throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
-    if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
-      throw new IllegalArgumentException("YUV image buffer is not large enough");
+    if (yuvImage.length < TJ.bufSizeYUV(width, align, height, subsamp))
+      throw new IllegalArgumentException("YUV buffer is not large enough");
 
     int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
     byte[][] planes = new byte[nc][];
@@ -296,9 +303,9 @@ public class YUVImage {
     int[] offsets = new int[nc];
 
     planes[0] = yuvImage;
-    strides[0] = pad(TJ.planeWidth(0, width, subsamp), pad);
+    strides[0] = pad(TJ.planeWidth(0, width, subsamp), align);
     if (subsamp != TJ.SAMP_GRAY) {
-      strides[1] = strides[2] = pad(TJ.planeWidth(1, width, subsamp), pad);
+      strides[1] = strides[2] = pad(TJ.planeWidth(1, width, subsamp), align);
       planes[1] = planes[2] = yuvImage;
       offsets[1] = offsets[0] +
         strides[0] * TJ.planeHeight(0, height, subsamp);
@@ -306,7 +313,7 @@ public class YUVImage {
         strides[1] * TJ.planeHeight(1, height, subsamp);
     }
 
-    yuvPad = pad;
+    yuvAlign = align;
     setBuf(planes, offsets, width, strides, height, subsamp);
   }
 
@@ -333,23 +340,23 @@ public class YUVImage {
   }
 
   /**
-   * Returns the line padding used in the YUV image buffer (if this image is
+   * Returns the row alignment (in bytes) of the YUV buffer (if this image is
    * stored in a unified buffer rather than separate image planes.)
    *
-   * @return the line padding used in the YUV image buffer
+   * @return the row alignment of the YUV buffer
    */
   public int getPad() {
     if (yuvPlanes == null)
       throw new IllegalStateException(NO_ASSOC_ERROR);
-    if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
+    if (yuvAlign < 1 || ((yuvAlign & (yuvAlign - 1)) != 0))
       throw new IllegalStateException("Image is not stored in a unified buffer");
-    return yuvPad;
+    return yuvAlign;
   }
 
   /**
-   * Returns the number of bytes per line of each plane in the YUV image.
+   * Returns the number of bytes per row of each plane in the YUV image.
    *
-   * @return the number of bytes per line of each plane in the YUV image
+   * @return the number of bytes per row of each plane in the YUV image
    */
   public int[] getStrides() {
     if (yuvStrides == null)
@@ -395,10 +402,10 @@ public class YUVImage {
   }
 
   /**
-   * Returns the YUV image buffer (if this image is stored in a unified
-   * buffer rather than separate image planes.)
+   * Returns the YUV buffer (if this image is stored in a unified buffer rather
+   * than separate image planes.)
    *
-   * @return the YUV image buffer
+   * @return the YUV buffer
    */
   public byte[] getBuf() {
     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
@@ -412,34 +419,34 @@ public class YUVImage {
   }
 
   /**
-   * Returns the size (in bytes) of the YUV image buffer (if this image is
-   * stored in a unified buffer rather than separate image planes.)
+   * Returns the size (in bytes) of the YUV buffer (if this image is stored in
+   * a unified buffer rather than separate image planes.)
    *
-   * @return the size (in bytes) of the YUV image buffer
+   * @return the size (in bytes) of the YUV buffer
    */
   public int getSize() {
     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
       throw new IllegalStateException(NO_ASSOC_ERROR);
     int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
-    if (yuvPad < 1)
+    if (yuvAlign < 1)
       throw new IllegalStateException("Image is not stored in a unified buffer");
     for (int i = 1; i < nc; i++) {
       if (yuvPlanes[i] != yuvPlanes[0])
         throw new IllegalStateException("Image is not stored in a unified buffer");
     }
-    return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
+    return TJ.bufSizeYUV(yuvWidth, yuvAlign, yuvHeight, yuvSubsamp);
   }
 
   private static int pad(int v, int p) {
     return (v + p - 1) & (~(p - 1));
   }
 
-  protected long handle = 0;
-  protected byte[][] yuvPlanes = null;
-  protected int[] yuvOffsets = null;
-  protected int[] yuvStrides = null;
-  protected int yuvPad = 0;
-  protected int yuvWidth = 0;
-  protected int yuvHeight = 0;
-  protected int yuvSubsamp = -1;
+  private long handle = 0;
+  private byte[][] yuvPlanes = null;
+  private int[] yuvOffsets = null;
+  private int[] yuvStrides = null;
+  private int yuvAlign = 1;
+  private int yuvWidth = 0;
+  private int yuvHeight = 0;
+  private int yuvSubsamp = -1;
 }
index 8ec4ecd..e27c3b5 100644 (file)
@@ -8,7 +8,7 @@
 extern "C" {
 #endif
 #undef org_libjpegturbo_turbojpeg_TJ_NUMSAMP
-#define org_libjpegturbo_turbojpeg_TJ_NUMSAMP 6L
+#define org_libjpegturbo_turbojpeg_TJ_NUMSAMP 7L
 #undef org_libjpegturbo_turbojpeg_TJ_SAMP_444
 #define org_libjpegturbo_turbojpeg_TJ_SAMP_444 0L
 #undef org_libjpegturbo_turbojpeg_TJ_SAMP_422
@@ -21,6 +21,10 @@ extern "C" {
 #define org_libjpegturbo_turbojpeg_TJ_SAMP_440 4L
 #undef org_libjpegturbo_turbojpeg_TJ_SAMP_411
 #define org_libjpegturbo_turbojpeg_TJ_SAMP_411 5L
+#undef org_libjpegturbo_turbojpeg_TJ_SAMP_441
+#define org_libjpegturbo_turbojpeg_TJ_SAMP_441 6L
+#undef org_libjpegturbo_turbojpeg_TJ_SAMP_UNKNOWN
+#define org_libjpegturbo_turbojpeg_TJ_SAMP_UNKNOWN -1L
 #undef org_libjpegturbo_turbojpeg_TJ_NUMPF
 #define org_libjpegturbo_turbojpeg_TJ_NUMPF 12L
 #undef org_libjpegturbo_turbojpeg_TJ_PF_RGB
@@ -59,16 +63,52 @@ extern "C" {
 #define org_libjpegturbo_turbojpeg_TJ_CS_CMYK 3L
 #undef org_libjpegturbo_turbojpeg_TJ_CS_YCCK
 #define org_libjpegturbo_turbojpeg_TJ_CS_YCCK 4L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_STOPONWARNING
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_STOPONWARNING 0L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_BOTTOMUP
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_BOTTOMUP 1L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_QUALITY
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_QUALITY 3L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_SUBSAMP
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_SUBSAMP 4L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_JPEGWIDTH
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_JPEGWIDTH 5L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_JPEGHEIGHT
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_JPEGHEIGHT 6L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_PRECISION
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_PRECISION 7L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_COLORSPACE
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_COLORSPACE 8L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_FASTUPSAMPLE
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_FASTUPSAMPLE 9L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_FASTDCT
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_FASTDCT 10L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_OPTIMIZE
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_OPTIMIZE 11L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_PROGRESSIVE
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_PROGRESSIVE 12L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_SCANLIMIT
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_SCANLIMIT 13L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_ARITHMETIC
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_ARITHMETIC 14L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESS
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESS 15L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESSPSV
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESSPSV 16L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESSPT
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_LOSSLESSPT 17L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_RESTARTBLOCKS
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_RESTARTBLOCKS 18L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_RESTARTROWS
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_RESTARTROWS 19L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_XDENSITY
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_XDENSITY 20L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_YDENSITY
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_YDENSITY 21L
+#undef org_libjpegturbo_turbojpeg_TJ_PARAM_DENSITYUNITS
+#define org_libjpegturbo_turbojpeg_TJ_PARAM_DENSITYUNITS 22L
 #undef org_libjpegturbo_turbojpeg_TJ_FLAG_BOTTOMUP
 #define org_libjpegturbo_turbojpeg_TJ_FLAG_BOTTOMUP 2L
-#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FORCEMMX
-#define org_libjpegturbo_turbojpeg_TJ_FLAG_FORCEMMX 8L
-#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE
-#define org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE 16L
-#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE2
-#define org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE2 32L
-#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE3
-#define org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE3 128L
 #undef org_libjpegturbo_turbojpeg_TJ_FLAG_FASTUPSAMPLE
 #define org_libjpegturbo_turbojpeg_TJ_FLAG_FASTUPSAMPLE 256L
 #undef org_libjpegturbo_turbojpeg_TJ_FLAG_FASTDCT
@@ -105,14 +145,6 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJ
- * Method:    bufSizeYUV
- * Signature: (III)I
- */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III
-  (JNIEnv *, jclass, jint, jint, jint);
-
-/*
- * Class:     org_libjpegturbo_turbojpeg_TJ
  * Method:    planeSizeYUV
  * Signature: (IIIII)I
  */
index e76bd0e..24bc521 100644 (file)
@@ -9,6 +9,22 @@ extern "C" {
 #endif
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
+ * Method:    set
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_set
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJCompressor
+ * Method:    get
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_get
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJCompressor
  * Method:    init
  * Signature: ()V
  */
@@ -25,75 +41,67 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    compress
- * Signature: ([BIIII[BIII)I
- */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
-  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
-
-/*
- * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    compress
- * Signature: ([BIIIIII[BIII)I
+ * Method:    compress8
+ * Signature: ([BIIIIII[B)I
  */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
-  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3BIIIIII_3B
+  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jint, jint, jbyteArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    compress
- * Signature: ([IIIII[BIII)I
+ * Method:    compress12
+ * Signature: ([SIIIIII[B)I
  */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
-  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress12
+  (JNIEnv *, jobject, jshortArray, jint, jint, jint, jint, jint, jint, jbyteArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    compress
- * Signature: ([IIIIIII[BIII)I
+ * Method:    compress16
+ * Signature: ([SIIIIII[B)I
  */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
-  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress16
+  (JNIEnv *, jobject, jshortArray, jint, jint, jint, jint, jint, jint, jbyteArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    compressFromYUV
- * Signature: ([[B[II[III[BII)I
+ * Method:    compress8
+ * Signature: ([IIIIIII[B)I
  */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII
-  (JNIEnv *, jobject, jobjectArray, jintArray, jint, jintArray, jint, jint, jbyteArray, jint, jint);
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3IIIIIII_3B
+  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jint, jint, jbyteArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    encodeYUV
- * Signature: ([BIIII[BII)V
+ * Method:    compressFromYUV8
+ * Signature: ([[B[II[II[B)I
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
-  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jbyteArray, jint, jint);
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV8
+  (JNIEnv *, jobject, jobjectArray, jintArray, jint, jintArray, jint, jbyteArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    encodeYUV
- * Signature: ([BIIIIII[[B[I[III)V
+ * Method:    encodeYUV8
+ * Signature: ([BIIIIII[[B[I[I)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III
-  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jint, jint, jobjectArray, jintArray, jintArray, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3BIIIIII_3_3B_3I_3I
+  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jint, jint, jobjectArray, jintArray, jintArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    encodeYUV
- * Signature: ([IIIII[BII)V
+ * Method:    encodeYUV8
+ * Signature: ([IIIIIII[[B[I[I)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII
-  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jbyteArray, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3IIIIIII_3_3B_3I_3I
+  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jint, jint, jobjectArray, jintArray, jintArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
- * Method:    encodeYUV
- * Signature: ([IIIIIII[[B[I[III)V
+ * Method:    loadImage
+ * Signature: (ILjava/lang/String;[II[I[I)Ljava/lang/Object;
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
-  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jint, jint, jobjectArray, jintArray, jintArray, jint, jint);
+JNIEXPORT jobject JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_loadImage
+  (JNIEnv *, jobject, jint, jstring, jintArray, jint, jintArray, jintArray);
 
 #ifdef __cplusplus
 }
index 2d58e73..621ad5f 100644 (file)
@@ -9,6 +9,22 @@ extern "C" {
 #endif
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
+ * Method:    set
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_set
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
+ * Method:    get
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_get
+  (JNIEnv *, jobject, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
  * Method:    init
  * Signature: ()V
  */
@@ -33,67 +49,75 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompress
- * Signature: ([BI[BIIIII)V
+ * Method:    setCroppingRegion
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_setCroppingRegion
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
+ * Method:    decompress8
+ * Signature: ([BI[BIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
-  (JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3BIIII
+  (JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompress
- * Signature: ([BI[BIIIIIII)V
+ * Method:    decompress12
+ * Signature: ([BI[SIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
-  (JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress12
+  (JNIEnv *, jobject, jbyteArray, jint, jshortArray, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompress
- * Signature: ([BI[IIIIII)V
+ * Method:    decompress16
+ * Signature: ([BI[SIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
-  (JNIEnv *, jobject, jbyteArray, jint, jintArray, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress16
+  (JNIEnv *, jobject, jbyteArray, jint, jshortArray, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompress
- * Signature: ([BI[IIIIIIII)V
+ * Method:    decompress8
+ * Signature: ([BI[IIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII
-  (JNIEnv *, jobject, jbyteArray, jint, jintArray, jint, jint, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3IIIII
+  (JNIEnv *, jobject, jbyteArray, jint, jintArray, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompressToYUV
- * Signature: ([BI[BI)V
+ * Method:    decompressToYUV8
+ * Signature: ([BI[[B[I[I)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI
-  (JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV8
+  (JNIEnv *, jobject, jbyteArray, jint, jobjectArray, jintArray, jintArray);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decompressToYUV
- * Signature: ([BI[[B[II[III)V
+ * Method:    decodeYUV8
+ * Signature: ([[B[I[I[BIIIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
-  (JNIEnv *, jobject, jbyteArray, jint, jobjectArray, jintArray, jint, jintArray, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3BIIIIII
+  (JNIEnv *, jobject, jobjectArray, jintArray, jintArray, jbyteArray, jint, jint, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decodeYUV
- * Signature: ([[B[I[II[BIIIIIII)V
+ * Method:    decodeYUV8
+ * Signature: ([[B[I[I[IIIIIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII
-  (JNIEnv *, jobject, jobjectArray, jintArray, jintArray, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3IIIIIII
+  (JNIEnv *, jobject, jobjectArray, jintArray, jintArray, jintArray, jint, jint, jint, jint, jint, jint);
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJDecompressor
- * Method:    decodeYUV
- * Signature: ([[B[I[II[IIIIIIII)V
+ * Method:    saveImage
+ * Signature: (ILjava/lang/String;Ljava/lang/Object;IIII)V
  */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
-  (JNIEnv *, jobject, jobjectArray, jintArray, jintArray, jint, jintArray, jint, jint, jint, jint, jint, jint, jint);
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_saveImage
+  (JNIEnv *, jobject, jint, jstring, jobject, jint, jint, jint, jint);
 
 #ifdef __cplusplus
 }
index a9dad4d..5d86033 100644 (file)
@@ -18,10 +18,10 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJTransformer
  * Method:    transform
- * Signature: ([BI[[B[Lorg/libjpegturbo/turbojpeg/TJTransform;I)[I
+ * Signature: ([BI[[B[Lorg/libjpegturbo/turbojpeg/TJTransform;)[I
  */
 JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
-  (JNIEnv *, jobject, jbyteArray, jint, jobjectArray, jobjectArray, jint);
+  (JNIEnv *, jobject, jbyteArray, jint, jobjectArray, jobjectArray);
 
 #ifdef __cplusplus
 }
index 84e7ecc..cbb3d13 100644 (file)
@@ -23,6 +23,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jcmaster.h"
 
 
 /*
@@ -90,8 +91,18 @@ jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
 
   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 @@ jpeg_finish_compress(j_compress_ptr cinfo)
       /* 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 == 16) {
+#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
+      } else if (cinfo->data_precision == 12) {
+        if (!(*cinfo->coef->compress_data_12) (cinfo, (J12SAMPIMAGE)NULL))
+          ERREXIT(cinfo, JERR_CANT_SUSPEND);
+      } else {
+        if (!(*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE)NULL))
+          ERREXIT(cinfo, JERR_CANT_SUSPEND);
+      }
     }
     (*cinfo->master->finish_pass) (cinfo);
   }
index aa2aad9..2053028 100644 (file)
@@ -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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #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 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
   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 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
  * 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,15 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
  */
 
 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;
 
+  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 +104,9 @@ jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
   }
 
   /* 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 +117,35 @@ jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
     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 +161,9 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
   }
 
   /* 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 +174,7 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
     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 +183,5 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
   cinfo->next_scanline += lines_per_iMCU_row;
   return lines_per_iMCU_row;
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 */
index 068232a..2a5dde2 100644 (file)
@@ -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 @@ typedef my_coef_controller *my_coef_ptr;
 
 
 /* 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 @@ start_pass_coef(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
   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 @@ start_pass_coef(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
  */
 
 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 @@ compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
         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 @@ compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
  */
 
 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 @@ compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
      */
     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 @@ compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
  */
 
 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 @@ compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
  */
 
 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));
index 303b322..8eba36c 100644 (file)
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2009-2012, 2015, D. R. Commander.
+ * Copyright (C) 2009-2012, 2015, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 
 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;
 
@@ -48,26 +49,29 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     outptr2 = output_buf[2][output_row];
     output_row++;
     for (col = 0; col < num_cols; col++) {
-      r = inptr[RGB_RED];
-      g = inptr[RGB_GREEN];
-      b = inptr[RGB_BLUE];
+      r = RANGE_LIMIT(inptr[RGB_RED]);
+      g = RANGE_LIMIT(inptr[RGB_GREEN]);
+      b = RANGE_LIMIT(inptr[RGB_BLUE]);
       inptr += RGB_PIXELSIZE;
-      /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+      /* 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 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
 
 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;
 
@@ -100,15 +105,18 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     outptr = output_buf[0][output_row];
     output_row++;
     for (col = 0; col < num_cols; col++) {
-      r = inptr[RGB_RED];
-      g = inptr[RGB_GREEN];
-      b = inptr[RGB_BLUE];
+      r = RANGE_LIMIT(inptr[RGB_RED]);
+      g = RANGE_LIMIT(inptr[RGB_GREEN]);
+      b = RANGE_LIMIT(inptr[RGB_BLUE]);
       inptr += RGB_PIXELSIZE;
       /* Y */
-      outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
-                               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 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
 
 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;
 
index bdc563c..cd3a6a7 100644 (file)
--- a/jccolor.c
+++ b/jccolor.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2012, 2015, D. R. Commander.
+ * Copyright (C) 2009-2012, 2015, 2022, D. R. Commander.
  * Copyright (C) 2014, MIPS Technologies, Inc., California.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jsimd.h"
-#include "jconfigint.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;
@@ -36,14 +40,14 @@ typedef my_color_converter *my_cconvert_ptr;
 
 /*
  * 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.
@@ -54,16 +58,16 @@ typedef my_color_converter *my_cconvert_ptr;
  *
  * 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))
 
@@ -74,15 +78,27 @@ typedef my_color_converter *my_cconvert_ptr;
  */
 
 #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().
+ * Thus, we mask the incoming 12-bit samples to guard against overrunning
+ * or underrunning the conversion tables.
+ */
+
+#if BITS_IN_JSAMPLE == 12
+#define RANGE_LIMIT(value)  ((value) & 0xFFF)
+#else
+#define RANGE_LIMIT(value)  (value)
+#endif
 
 
 /* Include inline routines for colorspace extensions */
@@ -197,6 +213,7 @@ typedef my_color_converter *my_cconvert_ptr;
 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;
@@ -206,15 +223,15 @@ rgb_ycc_start(j_compress_ptr cinfo)
     (*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
@@ -223,6 +240,9 @@ rgb_ycc_start(j_compress_ptr cinfo)
     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
 }
 
 
@@ -231,8 +251,8 @@ rgb_ycc_start(j_compress_ptr cinfo)
  */
 
 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:
@@ -279,8 +299,8 @@ rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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:
@@ -324,8 +344,8 @@ rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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:
@@ -373,14 +393,15 @@ rgb_rgb_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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;
 
@@ -392,28 +413,31 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     outptr3 = output_buf[3][output_row];
     output_row++;
     for (col = 0; col < num_cols; col++) {
-      r = MAXJSAMPLE - inptr[0];
-      g = MAXJSAMPLE - inptr[1];
-      b = MAXJSAMPLE - inptr[2];
+      r = _MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
+      g = _MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
+      b = _MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
       /* K passes through as-is */
       outptr3[col] = inptr[3];
       inptr += 4;
-      /* 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
 }
 
 
@@ -424,11 +448,11 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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;
@@ -452,11 +476,11 @@ grayscale_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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;
@@ -524,10 +548,13 @@ null_method(j_compress_ptr cinfo)
  */
 
 GLOBAL(void)
-jinit_color_converter(j_compress_ptr cinfo)
+_jinit_color_converter(j_compress_ptr cinfo)
 {
   my_cconvert_ptr cconvert;
 
+  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));
@@ -574,123 +601,116 @@ jinit_color_converter(j_compress_ptr cinfo)
     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:
+    if (cinfo->master->lossless &&
+        cinfo->in_color_space != cinfo->jpeg_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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:
+    if (cinfo->master->lossless && !IsExtRGB(cinfo->in_color_space))
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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:
+    if (cinfo->master->lossless &&
+        cinfo->in_color_space != cinfo->jpeg_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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._color_convert = jsimd_rgb_ycc_convert;
+      else
+#endif
+      {
         cconvert->pub.start_pass = rgb_ycc_start;
-        cconvert->pub.color_convert = rgb_ycc_convert;
+        cconvert->pub._color_convert = rgb_ycc_convert;
       }
     } else if (cinfo->in_color_space == JCS_YCbCr) {
-#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_CMYK:
+    if (cinfo->master->lossless &&
+        cinfo->in_color_space != cinfo->jpeg_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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:
+    if (cinfo->master->lossless &&
+        cinfo->in_color_space != cinfo->jpeg_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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;
@@ -699,12 +719,14 @@ jinit_color_converter(j_compress_ptr cinfo)
     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) */
index 7dae17a..7191ee7 100644 (file)
@@ -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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 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);
 
@@ -265,10 +265,14 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
       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 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
         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 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
               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 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
  */
 
 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 @@ convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
     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 @@ quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
 
 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 @@ forward_DCT(j_compress_ptr cinfo, jpeg_component_info *compptr,
 #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 @@ quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
 
 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 @@ forward_DCT_float(j_compress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jinit_forward_dct(j_compress_ptr cinfo)
   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 @@ jinit_forward_dct(j_compress_ptr cinfo)
   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/jcdiffct.c b/jcdiffct.c
new file mode 100644 (file)
index 0000000..0bae068
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * 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, 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;
+
+  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 */
index f4dfa1c..3fede05 100644 (file)
--- a/jchuff.c
+++ b/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-2023, 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.
  *
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#ifdef WITH_SIMD
 #include "jsimd.h"
-#include "jconfigint.h"
+#else
+#include "jchuff.h"             /* Declarations shared with jc*huff.c */
+#endif
 #include <limits.h>
 
 /*
@@ -102,7 +108,9 @@ typedef bit_buf_type simd_bit_buf_type;
 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) */
@@ -127,7 +135,9 @@ typedef struct {
   long *ac_count_ptrs[NUM_HUFF_TBLS];
 #endif
 
+#ifdef WITH_SIMD
   int simd;
+#endif
 } huff_entropy_encoder;
 
 typedef huff_entropy_encoder *huff_entropy_ptr;
@@ -141,7 +151,9 @@ typedef struct {
   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;
 
 
@@ -180,7 +192,9 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
     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];
@@ -220,6 +234,7 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
   }
 
   /* Initialize bit buffer to empty */
+#ifdef WITH_SIMD
   if (entropy->simd) {
     entropy->saved.put_buffer.simd = 0;
 #if defined(__aarch64__) && !defined(NEON_INTRINSICS)
@@ -227,7 +242,9 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
 #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;
   }
@@ -242,7 +259,7 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
  * 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)
@@ -318,12 +335,12 @@ jpeg_make_c_derived_tbl(j_compress_ptr cinfo, boolean isDC, int tblno,
   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];
@@ -500,6 +517,7 @@ flush_bits(working_state *state)
   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;
@@ -507,7 +525,9 @@ flush_bits(working_state *state)
     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;
   }
@@ -525,6 +545,7 @@ flush_bits(working_state *state)
     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)
@@ -532,7 +553,9 @@ flush_bits(working_state *state)
 #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;
   }
@@ -542,6 +565,8 @@ flush_bits(working_state *state)
 }
 
 
+#ifdef WITH_SIMD
+
 /* Encode a single block's worth of coefficients */
 
 LOCAL(boolean)
@@ -561,6 +586,8 @@ encode_one_block_simd(working_state *state, JCOEFPTR block, int last_dc_val,
   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)
@@ -569,6 +596,7 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
   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;
@@ -589,6 +617,11 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
 
   /* Find the number of bits needed for the magnitude of the coefficient */
   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,
@@ -614,6 +647,9 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
     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; \
@@ -695,7 +731,9 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
   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) {
@@ -705,6 +743,7 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
   }
 
   /* 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];
@@ -717,7 +756,9 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
       /* 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];
@@ -765,7 +806,9 @@ finish_pass_huff(j_compress_ptr cinfo)
   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))
@@ -801,6 +844,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
   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 */
 
@@ -817,7 +861,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
   /* 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 */
@@ -846,7 +890,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
       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 */
@@ -901,7 +945,7 @@ encode_mcu_gather(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
 
 /*
  * 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
@@ -933,11 +977,15 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
 {
 #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 */
 
@@ -952,28 +1000,41 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
    * 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;
+        }
       }
     }
 
@@ -983,7 +1044,10 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
 
     /* 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]++;
@@ -1003,15 +1067,24 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
   }
 
   /* 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);
-
-      bits[codesize[i]]++;
-    }
+  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]]++;
+  }
+
+  /* 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
@@ -1051,14 +1124,9 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
    * 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. */
index 314a232..21f17b8 100644 (file)
--- a/jchuff.h
+++ b/jchuff.h
@@ -3,8 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
  * 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
+ * malformed 12-bit JPEG image, and the absolute value of -32768 would overflow
+ * a signed 16-bit integer.
+ */
+typedef unsigned short UJCOEF;
 
 /* Derived data constructed for each Huffman table */
 
index 157353a..fe8a13a 100644 (file)
--- a/jcinit.c
+++ b/jcinit.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) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -21,7 +23,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
 
 
 /*
@@ -38,34 +40,101 @@ jinit_compress_master(j_compress_ptr cinfo)
 
   /* Preprocessing */
   if (!cinfo->raw_data_in) {
-    jinit_color_converter(cinfo);
-    jinit_downsampler(cinfo);
-    jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+    if (cinfo->data_precision == 16) {
+#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
+    } 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 {
+      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);
+
+  if (cinfo->master->lossless) {
+#ifdef C_LOSSLESS_SUPPORTED
+    /* Prediction, sample differencing, and point transform */
+    if (cinfo->data_precision == 16)
+      j16init_lossless_compressor(cinfo);
+    else if (cinfo->data_precision == 12)
+      j12init_lossless_compressor(cinfo);
+    else
+      jinit_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 == 16)
+      j16init_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
+      jinit_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+                                               cinfo->optimize_coding));
 #else
-    ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
 #endif
   } else {
-    if (cinfo->progressive_mode) {
+    if (cinfo->data_precision == 16)
+      ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+    /* Forward DCT */
+    if (cinfo->data_precision == 12)
+      j12init_forward_dct(cinfo);
+    else
+      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);
+        jinit_phuff_encoder(cinfo);
 #else
-      ERREXIT(cinfo, JERR_NOT_COMPILED);
+        ERREXIT(cinfo, JERR_NOT_COMPILED);
 #endif
-    } else
-      jinit_huff_encoder(cinfo);
+      } 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));
   }
 
-  /* 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 */);
+  if (cinfo->data_precision == 16)
+#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
+  else if (cinfo->data_precision == 12)
+    j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+  else
+    jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
 
   jinit_marker_writer(cinfo);
 
diff --git a/jclhuff.c b/jclhuff.c
new file mode 100644 (file)
index 0000000..ae41545
--- /dev/null
+++ b/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/jclossls.c b/jclossls.c
new file mode 100644 (file)
index 0000000..e9ba92a
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * 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, 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;
+
+  /* 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 */
index 3f23028..fe8fc0b 100644 (file)
@@ -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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #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 @@ typedef struct {
    * (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 @@ typedef my_main_controller *my_main_ptr;
 
 /* 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 @@ start_pass_main(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
   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 @@ start_pass_main(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
  */
 
 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,15 @@ process_data_simple_main(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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;
+
+  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 +162,12 @@ jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
     /* 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) */
index 801fbab..a064d4d 100644 (file)
@@ -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 @@ write_file_header(j_compress_ptr cinfo)
 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 @@ write_frame_header(j_compress_ptr cinfo)
   } 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 @@ write_scan_header(j_compress_ptr cinfo)
     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);
     }
   }
index c2b2600..7e1408f 100644 (file)
@@ -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-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
-#include "jpegcomp.h"
-#include "jconfigint.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"
 
 
 /*
@@ -69,11 +39,13 @@ GLOBAL(void)
 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
 
@@ -86,6 +58,7 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
   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
@@ -110,8 +83,12 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
   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)
+#ifdef C_LOSSLESS_SUPPORTED
+  if (cinfo->data_precision != 8 && cinfo->data_precision != 12 &&
+      cinfo->data_precision != 16)
+#else
+  if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+#endif
     ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
 
   /* Check that number of components won't exceed internal array sizes */
@@ -142,17 +119,17 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
     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,
@@ -165,15 +142,19 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
   }
 
   /* 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)
@@ -194,13 +175,29 @@ validate_script(j_compress_ptr cinfo)
   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++)
@@ -209,7 +206,7 @@ validate_script(j_compress_ptr cinfo)
     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;
   }
@@ -241,13 +238,10 @@ validate_script(j_compress_ptr cinfo)
        * 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 */
@@ -275,9 +269,25 @@ validate_script(j_compress_ptr cinfo)
       }
 #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];
@@ -309,7 +319,7 @@ validate_script(j_compress_ptr cinfo)
   }
 }
 
-#endif /* C_MULTISCAN_FILES_SUPPORTED */
+#endif /* NEED_SCAN_SCRIPT */
 
 
 LOCAL(void)
@@ -318,7 +328,7 @@ select_scan_parameters(j_compress_ptr cinfo)
 {
   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;
@@ -344,10 +354,12 @@ select_scan_parameters(j_compress_ptr cinfo)
     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;
+    }
   }
 }
 
@@ -359,6 +371,7 @@ per_scan_setup(j_compress_ptr cinfo)
 {
   int ci, mcublks, tmp;
   jpeg_component_info *compptr;
+  int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
 
   if (cinfo->comps_in_scan == 1) {
 
@@ -373,7 +386,7 @@ per_scan_setup(j_compress_ptr cinfo)
     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.
@@ -396,10 +409,10 @@ per_scan_setup(j_compress_ptr cinfo)
     /* 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;
 
@@ -409,7 +422,7 @@ per_scan_setup(j_compress_ptr cinfo)
       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;
@@ -481,7 +494,8 @@ prepare_for_pass(j_compress_ptr cinfo)
     /* 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;
@@ -590,22 +604,15 @@ finish_pass_master(j_compress_ptr cinfo)
 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;
 
-  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);
@@ -615,8 +622,33 @@ jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
     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 */
+  /* 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;
+  }
+
+  /* Validate parameters, determine derived values */
+  initial_setup(cinfo, transcode_only);
+
+  if (cinfo->master->lossless ||        /*  TEMPORARY HACK ??? */
+      (cinfo->progressive_mode && !cinfo->arith_code))
+    cinfo->optimize_coding = TRUE; /* assume default tables no good for
+                                      progressive mode or lossless mode */
+  if (cinfo->data_precision == 12 && !cinfo->arith_code)
+    cinfo->optimize_coding = TRUE; /* assume default tables no good for 12-bit
+                                      data precision */
 
   /* Initialize my private state */
   if (transcode_only) {
diff --git a/jcmaster.h b/jcmaster.h
new file mode 100644 (file)
index 0000000..3b13289
--- /dev/null
@@ -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;
index d162f3b..0e0b23e 100644 (file)
 /* for product VD */
 #define COLOR_PICKER_ENABLE @COLOR_PICKER_ENABLE@
 
-/* Support arithmetic encoding */
+/* Support arithmetic encoding when using 8-bit samples */
 #cmakedefine C_ARITH_CODING_SUPPORTED 1
 
-/* Support arithmetic decoding */
+/* Support arithmetic decoding when using 8-bit samples */
 #cmakedefine D_ARITH_CODING_SUPPORTED 1
 
 /* Support in-memory source/destination managers */
-#cmakedefine MEM_SRCDST_SUPPORTED 1
+#define MEM_SRCDST_SUPPORTED  1
 
-/* Use accelerated SIMD routines. */
+/* Use accelerated SIMD routines when using 8-bit samples */
 #cmakedefine WITH_SIMD 1
 
-/*
- * 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.
+/* 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
 
-#define BITS_IN_JSAMPLE  @BITS_IN_JSAMPLE@      /* use 8 or 12 */
+#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
index d087d7b..e7e66e7 100644 (file)
 #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
index 5bc7174..d1dee4d 100644 (file)
--- a/jcparam.c
+++ b/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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -202,7 +204,6 @@ jpeg_set_defaults(j_compress_ptr cinfo)
   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 */
@@ -232,7 +233,7 @@ jpeg_set_defaults(j_compress_ptr cinfo)
    * tables will be computed.  This test can be removed if default tables
    * are supplied that are valid for the desired precision.
    */
-  if (cinfo->data_precision > 8)
+  if (cinfo->data_precision == 12 && !cinfo->arith_code)
     cinfo->optimize_coding = TRUE;
 
   /* By default, use the simpler non-cosited sampling alignment */
@@ -296,7 +297,10 @@ jpeg_default_colorspace(j_compress_ptr cinfo)
   case JCS_EXT_BGRA:
   case JCS_EXT_ABGR:
   case JCS_EXT_ARGB:
-    jpeg_set_colorspace(cinfo, JCS_YCbCr);
+    if (cinfo->master->lossless)
+      jpeg_set_colorspace(cinfo, JCS_RGB);
+    else
+      jpeg_set_colorspace(cinfo, JCS_YCbCr);
     break;
   case JCS_YCbCr:
     jpeg_set_colorspace(cinfo, JCS_YCbCr);
@@ -475,6 +479,11 @@ jpeg_simple_progression(j_compress_ptr cinfo)
   if (cinfo->global_state != CSTATE_START)
     ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
 
+  if (cinfo->master->lossless) {
+    cinfo->master->lossless = FALSE;
+    jpeg_default_colorspace(cinfo);
+  }
+
   /* 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 +548,38 @@ jpeg_simple_progression(j_compress_ptr cinfo)
 }
 
 #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 */
index 872e570..56e63bd 100644 (file)
--- a/jcphuff.c
+++ b/jcphuff.c
@@ -3,9 +3,11 @@
  *
  * 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) 2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2016, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2020, Arm Limited.
  * Copyright (C) 2021, Alex Richardson.
  * For conditions of distribution and use, see the accompanying README.ijg
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#ifdef WITH_SIMD
 #include "jsimd.h"
-#include "jconfigint.h"
+#else
+#include "jchuff.h"             /* Declarations shared with jc*huff.c */
+#endif
 #include <limits.h>
 
 #ifdef HAVE_INTRIN_H
@@ -83,11 +88,11 @@ typedef struct {
   /* Pointer to routine to prepare data for encode_mcu_AC_first() */
   void (*AC_first_prepare) (const JCOEF *block,
                             const int *jpeg_natural_order_start, int Sl,
-                            int Al, JCOEF *values, size_t *zerobits);
+                            int Al, UJCOEF *values, size_t *zerobits);
   /* Pointer to routine to prepare data for encode_mcu_AC_refine() */
   int (*AC_refine_prepare) (const JCOEF *block,
                             const int *jpeg_natural_order_start, int Sl,
-                            int Al, JCOEF *absvalues, size_t *bits);
+                            int Al, UJCOEF *absvalues, size_t *bits);
 
   /* Mode flag: TRUE for optimization, FALSE for actual data output */
   boolean gather_statistics;
@@ -157,14 +162,14 @@ METHODDEF(boolean) encode_mcu_DC_first(j_compress_ptr cinfo,
                                        JBLOCKROW *MCU_data);
 METHODDEF(void) encode_mcu_AC_first_prepare
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *values, size_t *zerobits);
+   UJCOEF *values, size_t *zerobits);
 METHODDEF(boolean) encode_mcu_AC_first(j_compress_ptr cinfo,
                                        JBLOCKROW *MCU_data);
 METHODDEF(boolean) encode_mcu_DC_refine(j_compress_ptr cinfo,
                                         JBLOCKROW *MCU_data);
 METHODDEF(int) encode_mcu_AC_refine_prepare
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *absvalues, size_t *bits);
+   UJCOEF *absvalues, size_t *bits);
 METHODDEF(boolean) encode_mcu_AC_refine(j_compress_ptr cinfo,
                                         JBLOCKROW *MCU_data);
 METHODDEF(void) finish_pass_phuff(j_compress_ptr cinfo);
@@ -224,18 +229,22 @@ start_pass_phuff(j_compress_ptr cinfo, boolean gather_statistics)
       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)
@@ -490,6 +499,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
   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;
@@ -532,7 +542,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
     /* 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 */
@@ -584,8 +594,8 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
       continue; \
     /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ \
     temp2 ^= temp; \
-    values[k] = (JCOEF)temp; \
-    values[k + DCTSIZE2] = (JCOEF)temp2; \
+    values[k] = (UJCOEF)temp; \
+    values[k + DCTSIZE2] = (UJCOEF)temp2; \
     zerobits |= ((size_t)1U) << k; \
   } \
 }
@@ -593,7 +603,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
 METHODDEF(void)
 encode_mcu_AC_first_prepare(const JCOEF *block,
                             const int *jpeg_natural_order_start, int Sl,
-                            int Al, JCOEF *values, size_t *bits)
+                            int Al, UJCOEF *values, size_t *bits)
 {
   register int k, temp, temp2;
   size_t zerobits = 0U;
@@ -643,7 +653,7 @@ label \
     /* 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 */ \
@@ -666,11 +676,12 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
   register int nbits, r;
   int Sl = cinfo->Se - cinfo->Ss + 1;
   int Al = cinfo->Al;
-  JCOEF values_unaligned[2 * DCTSIZE2 + 15];
-  JCOEF *values;
-  const JCOEF *cvalue;
+  UJCOEF values_unaligned[2 * DCTSIZE2 + 15];
+  UJCOEF *values;
+  const UJCOEF *cvalue;
   size_t zerobits;
   size_t bits[8 / SIZEOF_SIZE_T];
+  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;
@@ -681,7 +692,7 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
       emit_restart(entropy, entropy->next_restart_num);
 
 #ifdef WITH_SIMD
-  cvalue = values = (JCOEF *)PAD((JUINTPTR)values_unaligned, 16);
+  cvalue = values = (UJCOEF *)PAD((JUINTPTR)values_unaligned, 16);
 #else
   /* Not using SIMD, so alignment is not needed */
   cvalue = values = values_unaligned;
@@ -815,7 +826,7 @@ encode_mcu_DC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
       zerobits |= ((size_t)1U) << k; \
       signbits |= ((size_t)(temp2 + 1)) << k; \
     } \
-    absvalues[k] = (JCOEF)temp; /* save abs value for main pass */ \
+    absvalues[k] = (UJCOEF)temp; /* save abs value for main pass */ \
     if (temp == 1) \
       EOB = k + koffset;        /* EOB = index of last newly-nonzero coef */ \
   } \
@@ -824,7 +835,7 @@ encode_mcu_DC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
 METHODDEF(int)
 encode_mcu_AC_refine_prepare(const JCOEF *block,
                              const int *jpeg_natural_order_start, int Sl,
-                             int Al, JCOEF *absvalues, size_t *bits)
+                             int Al, UJCOEF *absvalues, size_t *bits)
 {
   register int k, temp, temp2;
   int EOB = 0;
@@ -931,9 +942,9 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
   unsigned int BR;
   int Sl = cinfo->Se - cinfo->Ss + 1;
   int Al = cinfo->Al;
-  JCOEF absvalues_unaligned[DCTSIZE2 + 15];
-  JCOEF *absvalues;
-  const JCOEF *cabsvalue, *EOBPTR;
+  UJCOEF absvalues_unaligned[DCTSIZE2 + 15];
+  UJCOEF *absvalues;
+  const UJCOEF *cabsvalue, *EOBPTR;
   size_t zerobits, signbits;
   size_t bits[16 / SIZEOF_SIZE_T];
 
@@ -946,7 +957,7 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
       emit_restart(entropy, entropy->next_restart_num);
 
 #ifdef WITH_SIMD
-  cabsvalue = absvalues = (JCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16);
+  cabsvalue = absvalues = (UJCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16);
 #else
   /* Not using SIMD, so alignment is not needed */
   cabsvalue = absvalues = absvalues_unaligned;
index f27cc34..ac2311c 100644 (file)
@@ -1,8 +1,10 @@
 /*
  * 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.
  * For conditions of distribution and use, see the accompanying README.ijg
 #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 @@ typedef struct {
   /* 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 @@ start_pass_prep(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
  */
 
 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 @@ expand_bottom_edge(JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
  */
 
 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 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     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 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     }
     /* 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 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     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 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
  */
 
 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 @@ pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
       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 @@ pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
     }
     /* 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 @@ create_context_buffer(j_compress_ptr cinfo)
   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 @@ create_context_buffer(j_compress_ptr cinfo)
      * 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,15 @@ create_context_buffer(j_compress_ptr cinfo)
  */
 
 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;
+
+  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 +343,23 @@ jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
   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) */
index e8515eb..30e6e54 100644 (file)
@@ -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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #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 @@ start_pass_downsample(j_compress_ptr cinfo)
  */
 
 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 @@ expand_right_edge(JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
  */
 
 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 @@ sep_downsample(j_compress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
           outvalue += (JLONG)(*inptr++);
         }
       }
-      *outptr++ = (JSAMPLE)((outvalue + numpix2) / numpix);
+      *outptr++ = (_JSAMPLE)((outvalue + numpix2) / numpix);
     }
     inrow += v_expand;
   }
@@ -192,14 +198,16 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ fullsize_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
       /* 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 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
       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 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
     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,22 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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;
 
+  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 +499,17 @@ jinit_downsampler(j_compress_ptr cinfo)
     } 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 +519,11 @@ jinit_downsampler(j_compress_ptr cinfo)
       } 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 +539,5 @@ jinit_downsampler(j_compress_ptr cinfo)
     TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
 #endif
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
index e121028..ae52e39 100644 (file)
--- a/jctrans.c
+++ b/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 @@ LOCAL(void) transencode_coef_controller(j_compress_ptr cinfo,
 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 @@ jpeg_copy_critical_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
   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 @@ compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
 }
 
 
+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 @@ transencode_coef_controller(j_compress_ptr cinfo,
   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;
index f50c27e..51ca552 100644 (file)
@@ -3,6 +3,8 @@
  *
  * 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.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -23,7 +25,6 @@
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jdmaster.h"
-#include "jconfigint.h"
 
 
 /*
@@ -83,6 +84,8 @@ jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize)
   /* 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;
 
@@ -163,7 +166,10 @@ default_decompress_parms(j_decompress_ptr cinfo)
         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 */
+        if (cinfo->master->lossless)
+          cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */
+        else
+          cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
       }
     }
     /* Always guess RGB is proper output colorspace. */
index 02cd0cb..1f44927 100644 (file)
@@ -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-2023, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  */
 
 #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,20 @@ output_pass_setup(j_decompress_ptr cinfo)
       }
       /* Process some data */
       last_scanline = cinfo->output_scanline;
-      (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
-                                    &cinfo->output_scanline, (JDIMENSION)0);
+#ifdef D_LOSSLESS_SUPPORTED
+      if (cinfo->data_precision == 16)
+        (*cinfo->main->process_data_16) (cinfo, (J16SAMPARRAY)NULL,
+                                         &cinfo->output_scanline,
+                                         (JDIMENSION)0);
+      else
+#endif
+      if (cinfo->data_precision == 12)
+        (*cinfo->main->process_data_12) (cinfo, (J12SAMPARRAY)NULL,
+                                         &cinfo->output_scanline,
+                                         (JDIMENSION)0);
+      else
+        (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
+                                      &cinfo->output_scanline, (JDIMENSION)0);
       if (cinfo->output_scanline == last_scanline)
         return FALSE;           /* No progress made, must suspend */
     }
@@ -135,25 +154,29 @@ output_pass_setup(j_decompress_ptr cinfo)
 #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 +186,12 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
   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);
@@ -236,9 +265,11 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
     /* 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 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
 
   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,21 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
  * 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;
 
+  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 +332,36 @@ jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,
 
   /* 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 +375,27 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
 #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 +406,19 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
 #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 +457,7 @@ increment_simple_rowgroup_ctr(j_decompress_ptr cinfo, JDIMENSION rows)
  */
 
 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 +468,12 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
   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);
@@ -597,11 +646,17 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
  */
 
 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 +677,7 @@ jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
     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 +685,10 @@ jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
   return lines_per_iMCU_row;
 }
 
+#endif /* BITS_IN_JSAMPLE != 16 */
+
+
+#if BITS_IN_JSAMPLE == 8
 
 /* Additional entry points for buffered-image mode. */
 
@@ -687,3 +746,5 @@ jpeg_finish_output(j_decompress_ptr cinfo)
 }
 
 #endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+#endif /* BITS_IN_JSAMPLE == 8 */
index e10d981..cce263a 100644 (file)
@@ -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.
  *
@@ -24,7 +24,7 @@
 #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 +36,7 @@ typedef struct {
   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;
@@ -128,7 +128,7 @@ term_mem_destination(j_compress_ptr cinfo)
   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 +145,7 @@ term_mem_destination(j_compress_ptr cinfo)
 
 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;
index 6b4fed2..529f93b 100644 (file)
@@ -38,7 +38,6 @@ typedef my_destination_mgr *my_dest_ptr;
 #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 @@ typedef struct {
 } my_mem_destination_mgr;
 
 typedef my_mem_destination_mgr *my_mem_dest_ptr;
-#endif
 
 
 /*
@@ -74,13 +72,11 @@ init_destination(j_compress_ptr cinfo)
   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 @@ empty_output_buffer(j_compress_ptr cinfo)
   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 @@ empty_mem_output_buffer(j_compress_ptr cinfo)
 
   return TRUE;
 }
-#endif
 
 
 /*
@@ -179,7 +173,6 @@ term_destination(j_compress_ptr cinfo)
     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 @@ term_mem_destination(j_compress_ptr cinfo)
   *dest->outbuffer = dest->buffer;
   *dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
 }
-#endif
 
 
 /*
@@ -227,7 +219,6 @@ jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile)
 }
 
 
-#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 @@ jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer,
   dest->pub.next_output_byte = dest->buffer = *outbuffer;
   dest->pub.free_in_buffer = dest->bufsize = *outsize;
 }
-#endif
index 69fb5ea..a5970b5 100644 (file)
@@ -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 @@ term_source(j_decompress_ptr cinfo)
 
 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 @@ jpeg_mem_src_tj(j_decompress_ptr cinfo, const unsigned char *inbuffer,
   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;
 }
index e36a30d..dc135f4 100644 (file)
@@ -56,13 +56,11 @@ init_source(j_decompress_ptr cinfo)
   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 @@ fill_input_buffer(j_decompress_ptr cinfo)
   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 @@ fill_mem_input_buffer(j_decompress_ptr cinfo)
 
   return TRUE;
 }
-#endif
 
 
 /*
@@ -253,7 +249,6 @@ jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile)
 }
 
 
-#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 @@ jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer,
   src->bytes_in_buffer = (size_t)insize;
   src->next_input_byte = (const JOCTET *)inbuffer;
 }
-#endif
index 1fd170f..57784f2 100644 (file)
@@ -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
 
 #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 @@ start_output_pass(j_decompress_ptr cinfo)
   /* 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 @@ start_output_pass(j_decompress_ptr cinfo)
  */
 
 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;
 #if _USE_PRODUCT_TV
   /* region decoding. this limits decode to the set of blocks +- 1 outside
    * bounding blocks around the desired region to decode */
@@ -181,7 +182,7 @@ decompress_onepass(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
             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] +
@@ -314,7 +315,7 @@ consume_data(j_decompress_ptr cinfo)
  */
 
 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;
@@ -322,10 +323,10 @@ decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
   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 ||
@@ -354,7 +355,7 @@ decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
       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++) {
@@ -477,19 +478,20 @@ smoothing_ok(j_decompress_ptr cinfo)
  */
 
 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;
@@ -548,6 +550,7 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
          (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,
@@ -587,32 +590,33 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
       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
@@ -635,11 +639,11 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
         /* 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];
@@ -862,10 +866,13 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
  */
 
 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));
@@ -902,7 +909,7 @@ jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
          (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);
@@ -919,7 +926,7 @@ jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
       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 */
   }
 
index 9a0e780..bbe9e97 100644 (file)
@@ -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 @@ start_iMCU_row(j_decompress_ptr cinfo)
   coef->MCU_ctr = 0;
   coef->MCU_vert_offset = 0;
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
index 53c7bd9..2172d98 100644 (file)
@@ -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.
  *
 
 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 @@ ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
       *(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 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
       *(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 @@ rgb_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ gray_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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];
 
index 863c7a2..f22e29d 100644 (file)
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2015, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2015, 2022-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 
 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 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
                               ((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
                                                 SCALEBITS))];
       outptr[RGB_BLUE] =  range_limit[y + Cbbtab[cb]];
-      /* Set unused byte to 0xFF so it can be interpreted as an opaque */
-      /* 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] = 0xFF;
+      outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
       outptr += RGB_PIXELSIZE;
     }
   }
+#else
+  ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
 }
 
 
@@ -81,11 +85,11 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr = *output_buf++;
     for (col = 0; col < num_cols; col++) {
       outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
-      /* Set unused byte to 0xFF so it can be interpreted as an opaque */
-      /* 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] = 0xFF;
+      outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
       outptr += RGB_PIXELSIZE;
     }
@@ -111,12 +115,12 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
       outptr[RGB_RED] = inptr0[col];
       outptr[RGB_GREEN] = inptr1[col];
       outptr[RGB_BLUE] = inptr2[col];
-      /* Set unused byte to 0xFF so it can be interpreted as an opaque */
-      /* 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] = 0xFF;
+      outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
       outptr += RGB_PIXELSIZE;
     }
index 8da2b4e..e5c7b58 100644 (file)
--- a/jdcolor.c
+++ b/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, D. R. Commander.
  * Copyright (C) 2013, Linaro Limited.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jsimd.h"
-#include "jconfigint.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 */
@@ -34,6 +37,7 @@ typedef struct {
 
   /* 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;
@@ -44,7 +48,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
 
 /*
  * 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
@@ -53,7 +57,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
  *
  *      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
@@ -64,7 +68,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
  *
  * 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.
@@ -85,9 +89,9 @@ typedef my_color_deconverter *my_cconvert_ptr;
  */
 
 #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 */
@@ -210,6 +214,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
 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;
@@ -217,20 +222,20 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
 
   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);
@@ -243,6 +248,9 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
     /* 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
 }
 
 
@@ -251,8 +259,8 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
  */
 
 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:
@@ -301,6 +309,7 @@ ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 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;
@@ -310,11 +319,14 @@ build_rgb_y_table(j_decompress_ptr cinfo)
     (*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
 }
 
 
@@ -323,14 +335,15 @@ build_rgb_y_table(j_decompress_ptr cinfo)
  */
 
 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;
 
@@ -345,10 +358,13 @@ rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
       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
 }
 
 
@@ -358,10 +374,10 @@ rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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;
@@ -419,11 +435,11 @@ null_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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);
 }
 
 
@@ -432,8 +448,8 @@ grayscale_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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:
@@ -477,8 +493,8 @@ gray_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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:
@@ -525,17 +541,18 @@ rgb_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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;
@@ -554,16 +571,19 @@ ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
       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
 }
 
 
@@ -653,8 +673,8 @@ static INLINE boolean is_big_endian(void)
 
 
 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);
@@ -664,8 +684,8 @@ ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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);
@@ -675,8 +695,8 @@ ycc_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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);
@@ -686,8 +706,8 @@ rgb_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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);
@@ -697,8 +717,8 @@ rgb_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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);
@@ -708,8 +728,8 @@ gray_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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);
@@ -734,11 +754,14 @@ start_pass_dcolor(j_decompress_ptr cinfo)
  */
 
 GLOBAL(void)
-jinit_color_deconverter(j_decompress_ptr cinfo)
+_jinit_color_deconverter(j_decompress_ptr cinfo)
 {
   my_cconvert_ptr cconvert;
   int ci;
 
+  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));
@@ -773,19 +796,24 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
   /* 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:
+    if (cinfo->master->lossless &&
+        cinfo->jpeg_color_space != cinfo->out_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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);
@@ -802,65 +830,78 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
   case JCS_EXT_BGRA:
   case JCS_EXT_ABGR:
   case JCS_EXT_ARGB:
+    if (cinfo->master->lossless && cinfo->jpeg_color_space != JCS_RGB)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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:
+    if (cinfo->master->lossless)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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:
+    if (cinfo->master->lossless &&
+        cinfo->jpeg_color_space != cinfo->out_color_space)
+      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
     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;
@@ -869,7 +910,7 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
     /* 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;
@@ -880,3 +921,5 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
   else
     cinfo->output_components = cinfo->out_color_components;
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/jdct.h b/jdct.h
index 66d1718..0411a79 100644 (file)
--- a/jdct.h
+++ b/jdct.h
@@ -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) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
  * 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 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
@@ -76,78 +78,89 @@ 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
+ * 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 IDCT_range_limit(cinfo) \
+  ((_JSAMPLE *)((cinfo)->sample_range_limit) + _CENTERJSAMPLE)
 
-#define RANGE_MASK  (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+#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_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);
+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);
 
 
 /*
index e78d7be..0bd8c2b 100644 (file)
@@ -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 @@ start_pass(j_decompress_ptr cinfo)
   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 @@ start_pass(j_decompress_ptr cinfo)
     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 @@ start_pass(j_decompress_ptr cinfo)
       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 @@ start_pass(j_decompress_ptr cinfo)
       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 @@ start_pass(j_decompress_ptr cinfo)
       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 @@ start_pass(j_decompress_ptr cinfo)
  */
 
 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/jddiffct.c b/jddiffct.c
new file mode 100644 (file)
index 0000000..f1d7f61
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * 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, 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;
+
+  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 */
index 679d221..cd8c084 100644 (file)
--- a/jdhuff.c
+++ b/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 @@ start_pass_huff_decoder(j_decompress_ptr cinfo)
  * 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 @@ jpeg_make_d_derived_tbl(j_decompress_ptr cinfo, boolean isDC, int tblno,
 
   /* 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 @@ jpeg_make_d_derived_tbl(j_decompress_ptr cinfo, boolean isDC, int tblno,
 
 
 /*
- * 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.
index cfa0b7f..3eee002 100644 (file)
--- a/jdhuff.h
+++ b/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"
index 1bc5aff..136bef5 100644 (file)
--- a/jdinput.c
+++ b/jdinput.c
@@ -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, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  *
  * 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,6 +49,7 @@ initial_setup(j_decompress_ptr cinfo)
 {
   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 ||
@@ -53,7 +57,12 @@ initial_setup(j_decompress_ptr cinfo)
     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)
+#ifdef D_LOSSLESS_SUPPORTED
+  if (cinfo->data_precision != 8 && cinfo->data_precision != 12 &&
+      cinfo->data_precision != 16)
+#else
+  if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+#endif
     ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
 
   /* Check that number of components won't exceed internal array sizes */
@@ -78,36 +87,36 @@ initial_setup(j_decompress_ptr cinfo)
   }
 
 #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 +142,7 @@ initial_setup(j_decompress_ptr cinfo)
   /* 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 +159,7 @@ per_scan_setup(j_decompress_ptr cinfo)
 {
   int ci, mcublks, tmp;
   jpeg_component_info *compptr;
+  int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
 
   if (cinfo->comps_in_scan == 1) {
 
@@ -160,14 +170,14 @@ per_scan_setup(j_decompress_ptr cinfo)
     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 +197,22 @@ per_scan_setup(j_decompress_ptr cinfo)
     /* 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 +291,8 @@ METHODDEF(void)
 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 +301,8 @@ start_input_pass(j_decompress_ptr cinfo)
 
 /*
  * 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 +318,8 @@ finish_input_pass(j_decompress_ptr cinfo)
  * 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/jdlhuff.c b/jdlhuff.c
new file mode 100644 (file)
index 0000000..9964830
--- /dev/null
+++ b/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/jdlossls.c b/jdlossls.c
new file mode 100644 (file)
index 0000000..4d15e6b
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * 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, 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;
+
+  /* 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 */
index f466b25..c672b4b 100644 (file)
@@ -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, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 
 #include "jinclude.h"
 #include "jdmainct.h"
-#include "jconfigint.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)
  * 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
 
 /* 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
@@ -139,14 +141,15 @@ alloc_funny_pointers(j_decompress_ptr cinfo)
   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;
@@ -156,9 +159,9 @@ alloc_funny_pointers(j_decompress_ptr cinfo)
     /* 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);
@@ -180,7 +183,7 @@ make_funny_pointers(j_decompress_ptr cinfo)
   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++) {
@@ -220,7 +223,7 @@ set_bottom_pointers(j_decompress_ptr cinfo)
   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++) {
@@ -259,14 +262,14 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
   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;
@@ -274,7 +277,7 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
 #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:
@@ -290,7 +293,7 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
  */
 
 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;
@@ -298,7 +301,7 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
 
   /* 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 */
   }
@@ -311,9 +314,9 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
    */
 
   /* 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) {
@@ -329,15 +332,15 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
  */
 
 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 */
@@ -351,11 +354,11 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
   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;
@@ -375,11 +378,11 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
     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 */
@@ -406,12 +409,12 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
 #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 */
@@ -422,12 +425,15 @@ process_data_crank_post(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
  */
 
 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;
 
+  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));
@@ -453,9 +459,11 @@ jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
        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) */
index 37b201c..914ad11 100644 (file)
@@ -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 @@ typedef struct {
   /* 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 @@ set_wraparound_pointers(j_decompress_ptr cinfo)
   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 @@ set_wraparound_pointers(j_decompress_ptr cinfo)
     }
   }
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
index f7eba61..acd28ce 100644 (file)
@@ -3,6 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2012, 2015, 2022, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -237,7 +239,8 @@ get_soi(j_decompress_ptr cinfo)
 
 
 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;
@@ -246,6 +249,7 @@ get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
   INPUT_VARS(cinfo);
 
   cinfo->progressive_mode = is_prog;
+  cinfo->master->lossless = is_lossless;
   cinfo->arith_code = is_arith;
 
   INPUT_2BYTES(cinfo, length, return FALSE);
@@ -990,32 +994,40 @@ read_markers(j_decompress_ptr cinfo)
 
     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 */
index a3690bf..80a4842 100644 (file)
@@ -4,8 +4,10 @@
  * 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, D. R. Commander.
+ * Copyright (C) 2009-2011, 2016, 2019, 2022-2023, D. R. Commander.
  * Copyright (C) 2013, Linaro Limited.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -20,7 +22,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
 #include "jdmaster.h"
 
 
@@ -33,6 +35,9 @@ 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;
@@ -97,154 +102,154 @@ jpeg_core_output_dimensions(j_decompress_ptr cinfo)
   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;
-  }
+  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;
+    /* 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.
+     */
   }
-
-#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 */
 }
 
 
@@ -273,54 +278,56 @@ jpeg_calc_output_dimensions(j_decompress_ptr 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 (!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;
+      compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
 #else
-    compptr->DCT_scaled_size = ssize;
+      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.
-   */
+    }
 
+    /* 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... */
@@ -409,27 +416,83 @@ 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;
 
-  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));
+  if (cinfo->data_precision == 16) {
+#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
+  } 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 {
+    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));
+  }
 }
 
 
@@ -452,6 +515,17 @@ master_selection(j_decompress_ptr cinfo)
   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.
+   */
+  if (cinfo->master->lossless) {
+    cinfo->raw_data_out = FALSE;
+    cinfo->scale_num = cinfo->scale_denom = 1;
+  }
+
   /* Initialize dimensions and other stuff */
   jpeg_calc_output_dimensions(cinfo);
   prepare_range_limit_table(cinfo);
@@ -480,7 +554,8 @@ master_selection(j_decompress_ptr cinfo)
     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) {
+    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;
@@ -495,7 +570,12 @@ master_selection(j_decompress_ptr cinfo)
 
     if (cinfo->enable_1pass_quant) {
 #ifdef QUANT_1PASS_SUPPORTED
-      jinit_1pass_quantizer(cinfo);
+      if (cinfo->data_precision == 16)
+        ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+      else if (cinfo->data_precision == 12)
+        j12init_1pass_quantizer(cinfo);
+      else
+        jinit_1pass_quantizer(cinfo);
       master->quantizer_1pass = cinfo->cquantize;
 #else
       ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -505,7 +585,12 @@ master_selection(j_decompress_ptr cinfo)
     /* 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);
+      if (cinfo->data_precision == 16)
+        ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+      else if (cinfo->data_precision == 12)
+        j12init_2pass_quantizer(cinfo);
+      else
+        jinit_2pass_quantizer(cinfo);
       master->quantizer_2pass = cinfo->cquantize;
 #else
       ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -520,42 +605,122 @@ master_selection(j_decompress_ptr cinfo)
   if (!cinfo->raw_data_out) {
     if (master->using_merged_upsample) {
 #ifdef UPSAMPLE_MERGING_SUPPORTED
-      jinit_merged_upsampler(cinfo); /* does color conversion too */
+      if (cinfo->data_precision == 16)
+        ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+      else if (cinfo->data_precision == 12)
+        j12init_merged_upsampler(cinfo); /* does color conversion too */
+      else
+        jinit_merged_upsampler(cinfo); /* does color conversion too */
 #else
       ERREXIT(cinfo, JERR_NOT_COMPILED);
 #endif
     } else {
-      jinit_color_deconverter(cinfo);
-      jinit_upsampler(cinfo);
+      if (cinfo->data_precision == 16) {
+#ifdef D_LOSSLESS_SUPPORTED
+        j16init_color_deconverter(cinfo);
+        j16init_upsampler(cinfo);
+#else
+        ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+      } else if (cinfo->data_precision == 12) {
+        j12init_color_deconverter(cinfo);
+        j12init_upsampler(cinfo);
+      } else {
+        jinit_color_deconverter(cinfo);
+        jinit_upsampler(cinfo);
+      }
     }
-    jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+    if (cinfo->data_precision == 16)
+#ifdef D_LOSSLESS_SUPPORTED
+      j16init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+#else
+      ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+    else if (cinfo->data_precision == 12)
+      j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+    else
+      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);
+
+  if (cinfo->master->lossless) {
+#ifdef D_LOSSLESS_SUPPORTED
+    /* Prediction, sample undifferencing, point transform, and sample size
+     * scaling
+     */
+    if (cinfo->data_precision == 16)
+      j16init_lossless_decompressor(cinfo);
+    else if (cinfo->data_precision == 12)
+      j12init_lossless_decompressor(cinfo);
+    else
+      jinit_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 == 16)
+      j16init_d_diff_controller(cinfo, use_c_buffer);
+    else if (cinfo->data_precision == 12)
+      j12init_d_diff_controller(cinfo, use_c_buffer);
+    else
+      jinit_d_diff_controller(cinfo, use_c_buffer);
 #else
-    ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
 #endif
   } else {
-    if (cinfo->progressive_mode) {
+    if (cinfo->data_precision == 16)
+      ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+    /* Inverse DCT */
+    if (cinfo->data_precision == 12)
+      j12init_inverse_dct(cinfo);
+    else
+      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);
+        jinit_phuff_decoder(cinfo);
 #else
-      ERREXIT(cinfo, JERR_NOT_COMPILED);
+        ERREXIT(cinfo, JERR_NOT_COMPILED);
 #endif
-    } else
-      jinit_huff_decoder(cinfo);
-  }
+      } 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);
+    /* 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)
-    jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+  if (!cinfo->raw_data_out) {
+    if (cinfo->data_precision == 16)
+#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
+    else if (cinfo->data_precision == 12)
+      j12init_d_main_controller(cinfo,
+                                FALSE /* never need full buffer here */);
+    else
+      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);
index d8a0081..6d11bad 100644 (file)
--- a/jdmerge.c
+++ b/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.
@@ -42,7 +42,6 @@
 #include "jpeglib.h"
 #include "jdmerge.h"
 #include "jsimd.h"
-#include "jconfigint.h"
 
 #ifdef UPSAMPLE_MERGING_SUPPORTED
 
@@ -168,20 +167,20 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
 
   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);
@@ -220,14 +219,14 @@ start_pass_merged_upsample(j_decompress_ptr cinfo)
  */
 
 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 _USE_PRODUCT_TV
   int skip = 0;
@@ -239,11 +238,11 @@ merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     if (cinfo->out_color_space == JCS_RGB565)
       size = cinfo->output_width * 2;
 #if _USE_PRODUCT_TV
-    jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0, 1,
-                      upsample->out_row_width);
+    _jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+                       1, upsample->out_row_width);
 #else
-    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);
 #endif
     num_rows = 1;
     upsample->spare_full = FALSE;
@@ -293,9 +292,9 @@ merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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. */
 {
@@ -325,8 +324,8 @@ merged_1v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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:
@@ -370,8 +369,8 @@ h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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:
@@ -497,8 +496,8 @@ static INLINE boolean is_big_endian(void)
 
 
 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,
@@ -510,8 +509,8 @@ h2v1_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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,
@@ -523,8 +522,8 @@ h2v1_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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,
@@ -536,8 +535,8 @@ h2v2_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 
 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,
@@ -557,10 +556,13 @@ h2v2_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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));
@@ -571,10 +573,12 @@ jinit_merged_upsampler(j_decompress_ptr cinfo)
   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) {
@@ -584,14 +588,16 @@ jinit_merged_upsampler(j_decompress_ptr cinfo)
       }
     }
     /* 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) {
index b583396..73cbd60 100644 (file)
--- a/jdmerge.h
+++ b/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 @@ typedef struct {
   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 @@ typedef struct {
    * 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 */
index 980a4e2..0c719b9 100644 (file)
@@ -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.
  *
 
 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 @@ h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 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 @@ h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
 
 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 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 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;
index 9bf4f1a..8139e0a 100644 (file)
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2020, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2020, 2022-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 
 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 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr[RGB_GREEN] = range_limit[y + cgreen];
     outptr[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr[RGB_ALPHA] = 0xFF;
+    outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr += RGB_PIXELSIZE;
     y  = *inptr0++;
@@ -65,7 +65,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr[RGB_GREEN] = range_limit[y + cgreen];
     outptr[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr[RGB_ALPHA] = 0xFF;
+    outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr += RGB_PIXELSIZE;
   }
@@ -81,7 +81,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr[RGB_GREEN] = range_limit[y + cgreen];
     outptr[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr[RGB_ALPHA] = 0xFF;
+    outptr[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
   }
 }
@@ -93,18 +93,18 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr0[RGB_GREEN] = range_limit[y + cgreen];
     outptr0[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr0[RGB_ALPHA] = 0xFF;
+    outptr0[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr0 += RGB_PIXELSIZE;
     y  = *inptr00++;
@@ -139,7 +139,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr0[RGB_GREEN] = range_limit[y + cgreen];
     outptr0[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr0[RGB_ALPHA] = 0xFF;
+    outptr0[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr0 += RGB_PIXELSIZE;
     y  = *inptr01++;
@@ -147,7 +147,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr1[RGB_GREEN] = range_limit[y + cgreen];
     outptr1[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr1[RGB_ALPHA] = 0xFF;
+    outptr1[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr1 += RGB_PIXELSIZE;
     y  = *inptr01++;
@@ -155,7 +155,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr1[RGB_GREEN] = range_limit[y + cgreen];
     outptr1[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr1[RGB_ALPHA] = 0xFF;
+    outptr1[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     outptr1 += RGB_PIXELSIZE;
   }
@@ -171,14 +171,14 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     outptr0[RGB_GREEN] = range_limit[y + cgreen];
     outptr0[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr0[RGB_ALPHA] = 0xFF;
+    outptr0[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
     y  = *inptr01;
     outptr1[RGB_RED] =   range_limit[y + cred];
     outptr1[RGB_GREEN] = range_limit[y + cgreen];
     outptr1[RGB_BLUE] =  range_limit[y + cblue];
 #ifdef RGB_ALPHA
-    outptr1[RGB_ALPHA] = 0xFF;
+    outptr1[RGB_ALPHA] = _MAXJSAMPLE;
 #endif
   }
 }
index 9680ebc..bf97333 100644 (file)
--- a/jdphuff.c
+++ b/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>
 
 
index 6a2cf5c..d38495f 100644 (file)
@@ -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-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
 #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 @@ typedef struct {
    * 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 @@ typedef my_post_controller *my_post_ptr;
 
 
 /* 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 @@ start_pass_dpost(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
 
   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 @@ start_pass_dpost(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
  * 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 @@ post_process_1pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   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 @@ post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
   /* 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 @@ post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
   /* 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 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
     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 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   }
 }
 
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
 
 
 /*
@@ -251,10 +263,13 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
  */
 
 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;
 
+  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 +280,7 @@ jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
 
   /* 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 +301,15 @@ jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
 #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) */
index eaad72a..cc8015c 100644 (file)
@@ -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, D. R. Commander.
  * Copyright (C) 2014, MIPS Technologies, Inc., California.
  * Copyright (C) 2015, Google, Inc.
  * Copyright (C) 2019-2020, Arm Limited.
 #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 @@ start_pass_upsample(j_decompress_ptr cinfo)
  */
 
 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 @@ sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   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 @@ sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
 
 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 @@ fullsize_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ noop_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     }
     /* 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 @@ int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
       *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 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
       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 @@ h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 
 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 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
       /* 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 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 GLOBAL(void)
-jinit_upsampler(j_decompress_ptr cinfo)
+_jinit_upsampler(j_decompress_ptr cinfo)
 {
   my_upsample_ptr upsample;
   int ci;
@@ -418,13 +421,16 @@ jinit_upsampler(j_decompress_ptr cinfo)
   boolean need_buffer, do_fancy;
   int h_in_group, v_in_group, h_out_group, v_out_group;
 
+  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 +470,25 @@ jinit_upsampler(j_decompress_ptr cinfo)
     } 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 +499,25 @@ jinit_upsampler(j_decompress_ptr cinfo)
                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 +528,7 @@ jinit_upsampler(j_decompress_ptr cinfo)
     } 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 +536,5 @@ jinit_upsampler(j_decompress_ptr cinfo)
     }
   }
 }
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
index a6bf08a..a8a9298 100644 (file)
@@ -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 @@ typedef struct {
    * 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];
index d7ec4b8..719813f 100644 (file)
--- a/jdtrans.c
+++ b/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 @@ LOCAL(void) transdecode_master_selection(j_decompress_ptr cinfo);
 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 @@ transdecode_master_selection(j_decompress_ptr cinfo)
   }
 
   /* 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);
index eb44a11..39362fd 100644 (file)
--- a/jerror.h
+++ b/jerror.h
@@ -4,6 +4,8 @@
  * 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.
  * For conditions of distribution and use, see the accompanying README.ijg
@@ -53,7 +55,8 @@ JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
 #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_MCU_SIZE, "Sampling factors too large for interleaved scan")
 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")
@@ -180,7 +183,7 @@ JMESSAGE(JTRC_THUMB_PALETTE,
 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(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
 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
 
index 4c9ce0d..26070d1 100644 (file)
  */
 
 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;
index c95a3a7..974013f 100644 (file)
@@ -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.
  *
  */
 
 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;
index 5aee74e..ee3a31a 100644 (file)
@@ -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 @@ jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     /* 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];
 
index 89a20c9..68119b9 100644 (file)
@@ -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.
  *
  * 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
  */
 
 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 @@ jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     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;
index bb08748..c58592d 100644 (file)
@@ -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.
  *
  */
 
 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 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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 @@ jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
   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
index 1dd65a9..6521e3e 100644 (file)
@@ -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.
  *
  */
 
 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 @@ jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
     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 @@ jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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 @@ jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
 #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 @@ jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
  */
 
 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
index e8d983a..56e7a4b 100644 (file)
@@ -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 @@ static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name)
 
 #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/jlossls.h b/jlossls.h
new file mode 100644 (file)
index 0000000..ce41704
--- /dev/null
+++ b/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 */
index a40446f..dca8f5c 100644 (file)
--- a/jmemmgr.c
+++ b/jmemmgr.c
@@ -155,7 +155,9 @@ typedef my_memory_mgr *my_mem_ptr;
  */
 
 struct jvirt_sarray_control {
-  JSAMPARRAY mem_buffer;        /* => the in-memory buffer */
+  JSAMPARRAY mem_buffer;        /* => the in-memory buffer (if
+                                   cinfo->data_precision is 12, then this is
+                                   actually a J12SAMPARRAY) */
   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 +353,10 @@ alloc_small(j_common_ptr cinfo, int pool_id, size_t sizeofobject)
  * 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 +440,22 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
   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 == 16 ?
+                       sizeof(J16SAMPLE) : (data_precision == 12 ?
+                                            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 +464,11 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
     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 +477,68 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
     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 == 16) {
+#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;
+      }
+    }
 
-  /* 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;
+    return (JSAMPARRAY)result16;
+#else
+    ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision);
+    return NULL;
+#endif
+  } 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 result;
+    return (JSAMPARRAY)result12;
+  } else {
+    /* 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 * sample_size));
+      for (i = rowsperchunk; i > 0; i--) {
+        result[currow++] = workspace;
+        workspace += samplesperrow;
+      }
+    }
+
+    return result;
+  }
 }
 
 
@@ -640,6 +700,13 @@ realize_virt_arrays(j_common_ptr cinfo)
   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 == 16 ?
+                       sizeof(J16SAMPLE) : (data_precision == 12 ?
+                                            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 +717,10 @@ realize_virt_arrays(j_common_ptr cinfo)
   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 +775,7 @@ realize_virt_arrays(j_common_ptr cinfo)
         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 +818,15 @@ do_sarray_io(j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
 /* Do backing store read or write of a virtual sample array */
 {
   long bytesperrow, file_offset, byte_count, rows, thisrow, i;
-
-  bytesperrow = (long)ptr->samplesperrow * sizeof(JSAMPLE);
+  int data_precision = cinfo->is_decompressor ?
+                        ((j_decompress_ptr)cinfo)->data_precision :
+                        ((j_compress_ptr)cinfo)->data_precision;
+  size_t sample_size = data_precision == 16 ?
+                       sizeof(J16SAMPLE) : (data_precision == 12 ?
+                                            sizeof(J12SAMPLE) :
+                                            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 +840,42 @@ do_sarray_io(j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
     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 == 16) {
+#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
+    } 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 (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);
+    }
     file_offset += byte_count;
   }
 }
@@ -821,6 +923,13 @@ access_virt_sarray(j_common_ptr cinfo, jvirt_sarray_ptr ptr,
 {
   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 == 16 ?
+                       sizeof(J16SAMPLE) : (data_precision == 12 ?
+                                            sizeof(J12SAMPLE) :
+                                            sizeof(JSAMPLE));
 
   /* debugging check */
   if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
@@ -876,7 +985,7 @@ access_virt_sarray(j_common_ptr cinfo, jvirt_sarray_ptr ptr,
     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) {
index b33a991..89c7842 100644 (file)
@@ -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.
  *
  * 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
+#define MAXJSAMPLE       255
+#define CENTERJSAMPLE    128
 
-#endif /* BITS_IN_JSAMPLE == 8 */
 
+/* J12SAMPLE should be the smallest type that will hold the values 0..4095. */
 
-#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.
- */
+typedef short J12SAMPLE;
 
-typedef short JSAMPLE;
-#define GETJSAMPLE(value)  ((int)(value))
+#define MAXJ12SAMPLE     4095
+#define CENTERJ12SAMPLE  2048
+
+
+/* J16SAMPLE should be the smallest type that will hold the values 0..65535. */
 
-#define MAXJSAMPLE      4095
-#define CENTERJSAMPLE   2048
+typedef unsigned short J16SAMPLE;
 
-#endif /* BITS_IN_JSAMPLE == 12 */
+#define MAXJ16SAMPLE     65535
+#define CENTERJ16SAMPLE  32768
 
 
 /* Representation of a DCT frequency coefficient.
@@ -242,14 +242,16 @@ typedef int boolean;
 
 #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 @@ typedef int boolean;
 
 #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? */
similarity index 98%
rename from jpegcomp.h
rename to jpegapicomp.h
index c4834ac..bb3912e 100644 (file)
@@ -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
index 6af9e2a..6541420 100644 (file)
--- a/jpegint.h
+++ b/jpegint.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) 2015-2016, 2019, 2021, D. R. Commander.
+ * Copyright (C) 2015-2017, 2019, 2021-2022, D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * Copyright (C) 2021, Alex Richardson.
  * For conditions of distribution and use, see the accompanying README.ijg
  */
 
 
+/* 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 */
@@ -61,6 +74,9 @@ typedef __UINTPTR_TYPE__ JUINTPTR;
 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
@@ -80,6 +96,7 @@ struct jpeg_comp_master {
   /* 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) */
@@ -87,6 +104,12 @@ 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) */
@@ -97,12 +120,32 @@ struct jpeg_c_prep_controller {
                             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
 };
 
-/* Coefficient buffer control */
+/* 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 */
@@ -111,6 +154,14 @@ struct jpeg_color_converter {
   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 */
@@ -119,24 +170,47 @@ struct jpeg_downsampler {
   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 */
 };
 
-/* Forward DCT (also controls coefficient quantization) */
+/* 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);
 };
 
@@ -164,6 +238,7 @@ struct jpeg_decomp_master {
 
   /* 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;
@@ -193,14 +268,36 @@ 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
 };
 
-/* Coefficient buffer control */
+/* 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;
 };
@@ -213,6 +310,20 @@ struct jpeg_d_post_controller {
                              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 */
@@ -238,24 +349,42 @@ struct jpeg_marker_reader {
 /* 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 */
 };
 
-/* Inverse DCT (also performs dequantization) */
+/* 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) */
@@ -265,6 +394,16 @@ struct jpeg_upsampler {
                     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 */
 };
@@ -275,6 +414,14 @@ struct jpeg_color_deconverter {
   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 */
@@ -282,6 +429,8 @@ 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);
 };
@@ -323,36 +472,95 @@ 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);
 
@@ -362,6 +570,14 @@ 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);
index b2360a6..19e3cb7 100644 (file)
--- a/jpeglib.h
+++ b/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-2023,
+             D. R. Commander.
  * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
@@ -42,6 +45,13 @@ extern "C" {
  * 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 */
@@ -56,9 +66,9 @@ extern "C" {
  * 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
 
 
@@ -69,6 +79,20 @@ 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 J12SAMPLE *J12SAMPROW;      /* ptr to one image row of 12-bit pixel
+                                       samples. */
+typedef J12SAMPROW *J12SAMPARRAY;   /* ptr to some 12-bit sample rows (a 2-D
+                                       12-bit sample array) */
+typedef J12SAMPARRAY *J12SAMPIMAGE; /* a 3-D 12-bit sample array: top index is
+                                       color */
+
+typedef J16SAMPLE *J16SAMPROW;      /* ptr to one image row of 16-bit pixel
+                                       samples. */
+typedef J16SAMPROW *J16SAMPARRAY;   /* ptr to some 16-bit sample rows (a 2-D
+                                       16-bit sample array) */
+typedef J16SAMPARRAY *J16SAMPIMAGE; /* a 3-D 16-bit sample array: top index is
+                                       color */
+
 typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
 typedef JBLOCK *JBLOCKROW;      /* pointer to one row of coefficient blocks */
 typedef JBLOCKROW *JBLOCKARRAY;         /* a 2-D array of coefficient blocks */
@@ -134,17 +158,20 @@ typedef struct {
   /* 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;
@@ -155,8 +182,10 @@ typedef struct {
   /* 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 */
@@ -168,12 +197,12 @@ typedef struct {
 
   /* 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.
@@ -191,8 +220,12 @@ typedef struct {
 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: */
@@ -237,7 +270,8 @@ typedef enum {
   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. */
@@ -430,11 +464,13 @@ struct jpeg_compress_struct {
   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.
    */
 
   /*
@@ -448,12 +484,13 @@ struct jpeg_compress_struct {
   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 */
@@ -552,7 +589,12 @@ struct jpeg_decompress_struct {
    * 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 or 16, then this is
+                                   actually a J12SAMPARRAY or a J16SAMPARRAY,
+                                   so callers must type-cast it in order to
+                                   read/write 12-bit or 16-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.
@@ -662,15 +704,21 @@ struct jpeg_decompress_struct {
 #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 12 or 16, then this is
+                                   actually a J12SAMPLE pointer or a J16SAMPLE
+                                   pointer, so callers must type-cast it in
+                                   order to read 12-bit or 16-bit samples from
+                                   the array. */
 
   /*
    * These fields are valid during any one scan.
@@ -684,12 +732,13 @@ struct jpeg_decompress_struct {
   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.
@@ -854,6 +903,11 @@ struct jpeg_memory_mgr {
   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,
@@ -935,13 +989,11 @@ EXTERN(void) jpeg_destroy_decompress(j_decompress_ptr cinfo);
 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);
@@ -961,6 +1013,9 @@ EXTERN(void) jpeg_add_quant_table(j_compress_ptr cinfo, int which_tbl,
                                   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);
@@ -972,6 +1027,12 @@ EXTERN(void) jpeg_start_compress(j_compress_ptr cinfo,
 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
@@ -982,6 +1043,9 @@ EXTERN(void) jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo);
 /* 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,
@@ -1017,15 +1081,28 @@ EXTERN(boolean) jpeg_start_decompress(j_decompress_ptr cinfo);
 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);
index 73b83e1..2e914b9 100644 (file)
--- a/jquant1.c
+++ b/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.
  */
@@ -144,13 +145,13 @@ typedef struct {
   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 @@ select_ncolors(j_decompress_ptr cinfo, int Ncolors[])
 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 @@ LOCAL(void)
 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 @@ create_colormap(j_decompress_ptr cinfo)
   /* 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 @@ create_colormap(j_decompress_ptr cinfo)
       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 @@ LOCAL(void)
 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 @@ create_colorindex(j_decompress_ptr cinfo)
 
     /* 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 @@ make_odither_array(j_decompress_ptr cinfo, int ncolors)
   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 @@ create_odither_tables(j_decompress_ptr cinfo)
  */
 
 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 @@ color_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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 @@ color_quantize3(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
 
   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 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
 
 
 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 @@ quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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 @@ quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
 
 
 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 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
   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 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
   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 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
          * 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 @@ start_pass_1_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
   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 @@ start_pass_1_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
       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 @@ new_color_map_1_quant(j_decompress_ptr cinfo)
  */
 
 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 @@ jinit_1pass_quantizer(j_decompress_ptr cinfo)
   /* 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 @@ jinit_1pass_quantizer(j_decompress_ptr cinfo)
     alloc_fs_workspace(cinfo);
 }
 
-#endif /* QUANT_1PASS_SUPPORTED */
+#endif /* defined(QUANT_1PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
index 1c1db71..e91c5e2 100644 (file)
--- a/jquant2.c
+++ b/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 @@ static const int c_scales[3] = { R_SCALE, G_SCALE, B_SCALE };
  * 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 @@ typedef struct {
   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 @@ typedef my_cquantizer *my_cquantize_ptr;
  */
 
 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 @@ have_c2max:
    * 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;
@@ -510,14 +511,15 @@ compute_color(j_decompress_ptr cinfo, boxptr boxp, int icolor)
 
 #if _USE_PRODUCT_TV
   if(total != 0) {
-    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);
+#endif
+    ((_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);
+#if _USE_PRODUCT_TV
   }
-#else
-  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);
 #endif
 }
 
@@ -536,11 +538,11 @@ select_colors(j_decompress_ptr cinfo, int desired_colors)
   /* 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 */
@@ -631,7 +633,7 @@ select_colors(j_decompress_ptr cinfo, int desired_colors)
 
 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
@@ -673,7 +675,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
 
   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;
@@ -696,7 +698,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
       }
     }
 
-    x = cinfo->colormap[1][i];
+    x = ((_JSAMPARRAY)cinfo->colormap)[1][i];
     if (x < minc1) {
       tdist = (x - minc1) * C1_SCALE;
       min_dist += tdist * tdist;
@@ -718,7 +720,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
       }
     }
 
-    x = cinfo->colormap[2][i];
+    x = ((_JSAMPARRAY)cinfo->colormap)[2][i];
     if (x < minc2) {
       tdist = (x - minc2) * C2_SCALE;
       min_dist += tdist * tdist;
@@ -752,7 +754,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
   ncolors = 0;
   for (i = 0; i < numcolors; i++) {
     if (mindist[i] <= minmaxdist)
-      colorlist[ncolors++] = (JSAMPLE)i;
+      colorlist[ncolors++] = (_JSAMPLE)i;
   }
   return ncolors;
 }
@@ -760,7 +762,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
 
 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.
@@ -771,7 +773,7 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
   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 */
@@ -798,11 +800,11 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
   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;
@@ -821,7 +823,7 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
         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;
@@ -848,13 +850,13 @@ fill_inverse_cmap(j_decompress_ptr cinfo, int c0, int c1, int c2)
   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;
@@ -899,13 +901,13 @@ fill_inverse_cmap(j_decompress_ptr cinfo, int c0, int c1, int c2)
  */
 
 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;
@@ -926,15 +928,15 @@ pass2_no_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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;
@@ -943,19 +945,19 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
   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++) {
@@ -1000,8 +1002,8 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       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];
@@ -1021,7 +1023,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
       /* 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];
@@ -1072,7 +1074,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
 /*
  * 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
@@ -1081,7 +1083,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
  * 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.
  */
@@ -1095,22 +1097,22 @@ init_error_limit(j_decompress_ptr cinfo)
   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
@@ -1127,7 +1129,7 @@ finish_pass1(j_decompress_ptr cinfo)
   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;
@@ -1159,15 +1161,15 @@ start_pass_2_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
 
   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 */
@@ -1223,11 +1225,14 @@ new_color_map_2_quant(j_decompress_ptr cinfo)
  */
 
 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));
@@ -1238,7 +1243,8 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
   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 */
@@ -1261,10 +1267,10 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
     /* 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
@@ -1290,4 +1296,4 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
   }
 }
 
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/jsamplecomp.h b/jsamplecomp.h
new file mode 100644 (file)
index 0000000..f3f275e
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * 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_gif  j16init_read_gif
+#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_read_gif  j12init_read_gif
+#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_read_gif  jinit_read_gif
+#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/jsimd.h
index 6c20365..6ae021a 100644 (file)
--- a/jsimd.h
+++ b/jsimd.h
@@ -2,8 +2,8 @@
  * jsimd.h
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2011, 2014, 2022, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2020, Arm Limited.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
@@ -12,6 +12,8 @@
  *
  */
 
+#ifdef WITH_SIMD
+
 #include "jchuff.h"             /* Declarations shared with jcphuff.c */
 
 EXTERN(int) jsimd_can_rgb_ycc(void);
@@ -114,10 +116,12 @@ EXTERN(int) jsimd_can_encode_mcu_AC_first_prepare(void);
 
 EXTERN(void) jsimd_encode_mcu_AC_first_prepare
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *values, size_t *zerobits);
+   UJCOEF *values, size_t *zerobits);
 
 EXTERN(int) jsimd_can_encode_mcu_AC_refine_prepare(void);
 
 EXTERN(int) jsimd_encode_mcu_AC_refine_prepare
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *absvalues, size_t *bits);
+   UJCOEF *absvalues, size_t *bits);
+
+#endif /* WITH_SIMD */
diff --git a/jsimd_none.c b/jsimd_none.c
deleted file mode 100644 (file)
index 5b38a9f..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * jsimd_none.c
- *
- * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
- * Copyright (C) 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, JCOEF *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, JCOEF *absvalues, size_t *bits)
-{
-  return 0;
-}
index d862716..24caac1 100644 (file)
--- a/jutils.c
+++ b/jutils.c
 #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 @@ jround_up(long a, long b)
   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 @@ jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
   }
 }
 
+#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 @@ jzero_far(void *target, size_t bytestozero)
 {
   memset(target, 0, bytestozero);
 }
+
+#endif /* BITS_IN_JSAMPLE == 8 */
index dca4f08..42a4e73 100644 (file)
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2022, D. R. Commander.
+ * Copyright (C) 2010, 2012-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -37,7 +37,7 @@
  */
 
 #define JCOPYRIGHT \
-  "Copyright (C) 2009-2022 D. R. Commander\n" \
+  "Copyright (C) 2009-2023 D. R. Commander\n" \
   "Copyright (C) 2015, 2020 Google, Inc.\n" \
   "Copyright (C) 2019-2020 Arm Limited\n" \
   "Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
@@ -48,6 +48,7 @@
   "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) 1999 Ken Murchison\n" \
   "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
 
 #define JCOPYRIGHT_SHORT \
index 309f9d3..2dae2d2 100644 (file)
@@ -2,8 +2,10 @@ 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.
+Lossless JPEG Modifications:
+Copyright (C) 1999, Ken Murchison.
 libjpeg-turbo Modifications:
-Copyright (C) 2010, 2014-2018, 2020, 2022, D. R. Commander.
+Copyright (C) 2010, 2014-2018, 2020, 2022-2023, D. R. Commander.
 Copyright (C) 2015, Google, Inc.
 For conditions of distribution and use, see the accompanying README.ijg file.
 
@@ -11,8 +13,8 @@ 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
+The file example.c provides heavily commented 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.
 
@@ -29,6 +31,7 @@ TABLE OF CONTENTS
 
 Overview:
         Functions provided by the library
+        12-bit and 16-bit Data Precision
         Outline of typical usage
 Basic library usage:
         Data formats
@@ -96,12 +99,10 @@ 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.
+We support 8-bit (lossy and lossless), 12-bit (lossy and lossless), and 16-bit
+(lossless) data precision.
 
 By itself, the library handles only interchange JPEG datastreams --- in
 particular the widely used JFIF file format.  The library can be used by
@@ -110,6 +111,58 @@ are embedded in more complex file formats.  (For example, this library is
 used by the free LIBTIFF library to support JPEG compression in TIFF.)
 
 
+12-bit and 16-bit Data Precision
+--------------------------------
+
+The JPEG standard provides for baseline 8-bit and 12-bit DCT processes as well
+as 8-bit, 12-bit, and 16-bit lossless (predictive) processes.  This code
+supports 12-bit-per-component lossy or lossless JPEG if you set
+cinfo->data_precision to 12 and 16-bit-per-component lossless JPEG if you set
+cinfo->data_precision to 16.  Note that this causes the sample size 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,
+PGM, and GIF file formats and 16-bit mode only for PPM and PGM file formats.
+
+Note that, when 12-bit data precision is enabled, the 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.
+
+Functions that are specific to 12-bit data precision have a prefix of "jpeg12_"
+instead of "jpeg_" and use the following data types and macros:
+
+  * J12SAMPLE instead of JSAMPLE
+  * J12SAMPROW instead of JSAMPROW
+  * J12SAMPARRAY instead of JSAMPARRAY
+  * J12SAMPIMAGE instead of JSAMPIMAGE
+  * MAXJ12SAMPLE instead of MAXJSAMPLE
+  * CENTERJ12SAMPLE instead of CENTERJSAMPLE
+
+Functions that are specific to 16-bit data precision have a prefix of "jpeg16_"
+instead of "jpeg_" and use the following data types and macros:
+
+  * J16SAMPLE instead of JSAMPLE
+  * J16SAMPROW instead of JSAMPROW
+  * J16SAMPARRAY instead of JSAMPARRAY
+  * J16SAMPIMAGE instead of JSAMPIMAGE
+  * MAXJ16SAMPLE instead of MAXJSAMPLE
+  * CENTERJ16SAMPLE instead of CENTERJSAMPLE
+
+This allows 8-bit, 12-bit, and 16-bit data precision to be used in a single
+application.  (Refer to example.c).  Arithmetic coding and SIMD acceleration
+are not currently implemented for 12-bit data precision, nor are they
+implemented for lossless mode with any data precision.
+
+Refer to the descriptions of the data_precision compression and decompression
+parameters below for further information.
+
+This documentation uses "J*SAMPLE", "J*SAMPROW", "J*SAMPARRAY", and
+"J*SAMPIMAGE" to generically refer to the 8-bit, 12-bit, or 16-bit data types.
+
+
 Outline of typical usage
 ------------------------
 
@@ -120,7 +173,10 @@ The rough outline of a JPEG compression operation is:
         Set parameters for compression, including image size & colorspace
         jpeg_start_compress(...);
         while (scan lines remain to be written)
-                jpeg_write_scanlines(...);
+                jpeg_write_scanlines(...);  /* Use jpeg12_write_scanlines() for
+                                               12-bit data precision and
+                                               jpeg16_write_scanlines() for
+                                               16-bit data precision. */
         jpeg_finish_compress(...);
         Release the JPEG compression object
 
@@ -132,7 +188,7 @@ 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
+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",
@@ -147,7 +203,10 @@ Similarly, the rough outline of a JPEG decompression operation is:
         Set parameters for decompression
         jpeg_start_decompress(...);
         while (scan lines remain to be read)
-                jpeg_read_scanlines(...);
+                jpeg_read_scanlines(...);  /* Use jpeg12_read_scanlines() for
+                                              12-bit data precision and
+                                              jpeg16_read_scanlines() for
+                                              16-bit data precision. */
         jpeg_finish_decompress(...);
         Release the JPEG decompression object
 
@@ -160,7 +219,7 @@ 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().
+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,
@@ -208,16 +267,16 @@ 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.)
+array of data type JSAMPLE or J12SAMPLE --- which is typically "unsigned char"
+or "short" (respectively), 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.
+pointer array to conform to this structure.  Pointers to J*SAMPLE rows are of
+type J*SAMPROW, and the pointer to the pointer array is of type J*SAMPARRAY.
 
 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
@@ -226,24 +285,24 @@ 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.)
+cinfo->data_precision (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, set cinfo->data_precision = 12 or 16.
 
 
 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;
+output then the returned data array contains a single J*SAMPLE 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,
+a 2-D J*SAMPARRAY 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).
+J*SAMPLEs, the maximum number of colors is limited by the size of J*SAMPLE
+(ie, at most 256 colors for 8-bit data precision, 4096 colors for 12-bit data
+precision, and 65536 colors for 16-bit data precision).
 
 
 Compression details
@@ -380,9 +439,12 @@ the compression cycle.
 
 
 5. while (scan lines remain to be written)
-        jpeg_write_scanlines(...);
+        jpeg_write_scanlines(...);  /* Use jpeg12_write_scanlines() for 12-bit
+                                       data precision and
+                                       jpeg16_write_scanlines() for 16-bit data
+                                       precision. */
 
-Now write all the required image data by calling 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
@@ -402,20 +464,24 @@ 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
+example.c 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 */
+        JSAMPROW row_pointer[1];        /* pointer to a single row
+                                           Use J12SAMPROW for 12-bit data
+                                           precision and J16SAMPROW for 16-bit
+                                           data precision. */
 
         while (cinfo.next_scanline < cinfo.image_height) {
-            row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
+            row_pointer[0] = image_buffer[cinfo.next_scanline];
             jpeg_write_scanlines(&cinfo, row_pointer, 1);
+                                        /* Use jpeg12_write_scanlines() for
+                                           12-bit data precision and
+                                           jpeg16_write_scanlines() for 16-bit
+                                           data precision. */
         }
 
-jpeg_write_scanlines() returns the number of scanlines actually written.
+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,
@@ -640,11 +706,11 @@ colormapped output has been requested.  Useful fields include
         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
+equals out_color_components.  It is the number of J*SAMPLE 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
+You will need output_width * output_components J*SAMPLEs 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
@@ -656,11 +722,14 @@ relevant parameters (scaling, output color space, and quantization flag).
 
 
 6. while (scan lines remain to be read)
-        jpeg_read_scanlines(...);
+        jpeg_read_scanlines(...);  /* Use jpeg12_read_scanlines() for 12-bit
+                                      data precision and
+                                      jpeg16_read_scanlines() for 16-bit data
+                                      precision. */
 
-Now you can read the decompressed image data by calling 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()
+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
@@ -680,13 +749,13 @@ 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
+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
+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
+always provide a loop that calls jpeg*_read_scanlines() repeatedly until the
 whole image has been read.
 
 
@@ -744,33 +813,34 @@ partial image decompression:
 1. Skipping rows when decompressing
 
         jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines);
+                /* Use jpeg12_skip_scanlines() for 12-bit data precision. */
 
 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
+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
+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,
+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
+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
+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
+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
+    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.
@@ -778,18 +848,19 @@ potential drawbacks:
        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().)
+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)
+                /* Use jpeg12_crop_scanline() for 12-bit data precision. */
 
 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().
+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
@@ -799,12 +870,12 @@ 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
+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().
+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"
@@ -949,6 +1020,30 @@ jpeg_simple_progression (j_compress_ptr cinfo)
         unless you want to make a custom scan sequence.  You must ensure that
         the JPEG color space is set correctly before calling this routine.
 
+jpeg_enable_lossless (j_compress_ptr cinfo, int predictor_selection_value,
+                      int point_transform)
+        Enables lossless mode with the specified predictor selection value
+        (1 - 7) and optional point transform (0 - {precision}-1, where
+        {precision} is the JPEG data precision).  A point transform value of 0
+        is necessary in order to create 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.)  Note that the following features will be unavailable
+        when compressing or decompressing lossless JPEG images:
+          * Partial image decompression
+          * Quality/quantization table selection
+          * DCT/IDCT algorithm selection
+          * Smoothing
+          * Downsampling/upsampling
+          * Color space conversion (the JPEG image will use the same color
+            space as the input image)
+          * Color quantization
+          * IDCT scaling
+          * Raw (downsampled) data input/output
+          * Transcoding of DCT coefficients
+        Any parameters used to enable or configure those features will be
+        ignored.
+
 
 Compression parameters (cinfo fields) include:
 
@@ -956,6 +1051,15 @@ boolean arith_code
         If TRUE, use arithmetic coding.
         If FALSE, use Huffman coding.
 
+int data_precision
+        To create a 12-bit-per-component JPEG file, set data_precision to 12
+        prior to calling jpeg_start_compress() or using the memory manager,
+        then use jpeg12_write_scanlines() or jpeg12_write_raw_data() instead of
+        jpeg_write_scanlines() or jpeg_write_raw_data().  To create a
+        16-bit-per-component lossless JPEG file, set data_precision to 16 prior
+        to calling jpeg_start_compress() or using the memory manager, then use
+        jpeg16_write_scanlines() instead of jpeg_write_scanlines().
+
 J_DCT_METHOD dct_method
         Selects the algorithm used for the DCT step.  Choices are:
                 JDCT_ISLOW: accurate integer method
@@ -1010,15 +1114,15 @@ boolean optimize_coding
 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.
+        Set restart_interval to specify the exact interval in MCU blocks
+        (samples in lossless mode).  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
@@ -1176,6 +1280,14 @@ 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:
 
+int data_precision                      Data precision (bits per component)
+        If data_precision is 12, then use jpeg12_read_scanlines(),
+        jpeg12_skip_scanlines(), jpeg12_crop_scanline(), and/or
+        jpeg12_read_raw_data() instead of jpeg_read_scanlines(),
+        jpeg_skip_scanlines(), jpeg_crop_scanline(), and/or
+        jpeg_read_raw_data().  If data_precision is 16, then use
+        jpeg16_read_scanlines() instead of jpeg_read_scanlines().
+
 JDIMENSION image_width                  Width and height of image
 JDIMENSION image_height
 int num_components                      Number of color components
@@ -1259,6 +1371,9 @@ JSAMPARRAY colormap
         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.
+        CAUTION: if data_precision is 12 or 16, then this is actually a
+        J12SAMPARRAY or a J16SAMPARRAY, so it must be type-cast in order to
+        read/write 12-bit or 16-bit samples from/to the array.
 
 int actual_number_of_colors
         The number of colors in the color map.
@@ -1338,10 +1453,10 @@ 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.
+are required to be output_width * output_components J*SAMPLEs 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
+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).
@@ -1445,7 +1560,7 @@ 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
+The file example.c 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
@@ -1462,7 +1577,7 @@ You may, if you wish, simply replace the entire JPEG error handling module
 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.
+example.c.
 
 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
@@ -1473,7 +1588,7 @@ 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
+additional fields.  Again, see example.c 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.)
@@ -1725,10 +1840,10 @@ 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
+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()
+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
@@ -1744,7 +1859,7 @@ 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
+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.
 
@@ -1778,11 +1893,11 @@ 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
+  * 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(),
+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
@@ -1919,7 +2034,7 @@ 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
+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
@@ -1967,7 +2082,10 @@ The basic control flow for buffered-image decoding is
             adjust output decompression parameters if required
             jpeg_start_output()         /* start a new output pass */
             for (all scanlines in image) {
-                jpeg_read_scanlines()
+                jpeg_read_scanlines()   /* Use jpeg12_read_scanlines() for
+                                           12-bit data precision and
+                                           jpeg16_read_scanlines() for 16-bit
+                                           data precision. */
                 display scanlines
             }
             jpeg_finish_output()        /* terminate output pass */
@@ -1997,7 +2115,7 @@ 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()
+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
@@ -2161,7 +2279,7 @@ 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
+* 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.
@@ -2520,7 +2638,7 @@ 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
+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
@@ -2662,9 +2780,9 @@ 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.
+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
@@ -2700,8 +2818,8 @@ 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
+namely a J*SAMPIMAGE array.  This is an array of pointers to two-dimensional
+arrays, each of type J*SAMPARRAY.  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
@@ -2713,8 +2831,9 @@ 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
+compression, except that you call jpeg_write_raw_data() or
+jpeg12_write_raw_data() in place of jpeg_write_scanlines() or
+jpeg12_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.
@@ -2727,13 +2846,13 @@ the following:
     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
+To pass raw data to the library, call jpeg*_write_raw_data() in place of
+jpeg*_write_scanlines().  The routines work similarly except that
+jpeg*_write_raw_data takes a J*SAMPIMAGE data array rather than J*SAMPARRAY.
+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
+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
@@ -2764,7 +2883,7 @@ 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
+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
@@ -2772,7 +2891,7 @@ 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.
+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.
 
 
@@ -2786,10 +2905,11 @@ 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.
+Then call jpeg_read_raw_data() or jpeg12_read_raw_data() in place of
+jpeg_read_scanlines() or jpeg12_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
+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
@@ -2799,7 +2919,7 @@ 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
+module suspends, jpeg*_read_raw_data() will return 0.  You can also use
 buffered-image mode to read raw data in multiple passes.
 
 
@@ -2814,7 +2934,7 @@ 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
+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
@@ -2855,7 +2975,7 @@ 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
+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
@@ -2899,7 +3019,7 @@ 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
+(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.
@@ -2910,8 +3030,8 @@ 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
+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.)
@@ -3033,9 +3153,9 @@ 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
+32-bit ints.  For 12-bit and 16-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
@@ -3058,23 +3178,6 @@ 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.
@@ -3084,7 +3187,7 @@ 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
+You probably don't want to make J*SAMPLE be int unless you have lots of memory
 to burn.
 
 You can reduce the size of the library by compiling out various optional
index 491533e..0f2920e 100644 (file)
@@ -1,7 +1,7 @@
 %define libver  8.2.2
 
 Name:           libjpeg-turbo
-Version:        2.1.4
+Version:        3.0.1
 Release:        1
 Summary:        A MMX/SSE2 accelerated library for manipulating JPEG image files
 License:        BSD License (BSD 3-clause, Historic Permission Notice and Disclaimer, libjpeg License)
@@ -103,6 +103,6 @@ rm -rf %{buildroot}%{_mandir}/man1/
 %{_libdir}/libturbojpeg.so
 %{_libdir}/libjpeg.so
 %{_libdir}/cmake/%{name}/*.cmake
-%doc coderules.txt jconfig.txt libjpeg.txt structure.txt example.txt
+%doc coderules.txt jconfig.txt libjpeg.txt structure.txt
 
 %changelog
diff --git a/rdbmp.c b/rdbmp.c
index 433ebe2..88ee751 100644 (file)
--- a/rdbmp.c
+++ b/rdbmp.c
@@ -670,6 +670,9 @@ jinit_read_bmp(j_compress_ptr cinfo, boolean use_inversion_array)
 {
   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,
index d2ed95c..836685e 100644 (file)
@@ -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.
  *
  * 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 @@ add_map_entry(j_decompress_ptr cinfo, int R, int G, int B)
   }
 
   /* 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 @@ read_ppm_map(j_decompress_ptr cinfo, FILE *infile)
     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 @@ read_ppm_map(j_decompress_ptr cinfo, FILE *infile)
  */
 
 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 @@ read_color_map(j_decompress_ptr cinfo, FILE *infile)
   }
 }
 
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
 #endif /* QUANT_2PASS_SUPPORTED */
diff --git a/rdgif.c b/rdgif.c
index bdf7401..0cbd279 100644 (file)
--- a/rdgif.c
+++ b/rdgif.c
  */
 
 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
+#include "jsamplecomp.h"
 
-#ifdef GIF_SUPPORTED
+#if defined(GIF_SUPPORTED) && \
+    (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED))
 
 
 /* Macros to deal with unsigned chars as efficiently as compiler allows */
@@ -89,7 +91,7 @@ typedef struct {
 
   j_compress_ptr cinfo;         /* back link saves passing separate parm */
 
-  JSAMPARRAY colormap;          /* GIF colormap (converted to my format) */
+  _JSAMPARRAY colormap;         /* GIF colormap (converted to my format) */
 
   /* State for GetCode and LZWReadByte */
   U_CHAR code_buf[256 + 4];     /* current input data block */
@@ -342,7 +344,7 @@ LZWReadByte(gif_source_ptr sinfo)
 
 
 LOCAL(void)
-ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
+ReadColorMap(gif_source_ptr sinfo, int cmaplen, _JSAMPARRAY cmap)
 /* Read a GIF colormap */
 {
   int i, gray = 1;
@@ -353,9 +355,9 @@ ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)
 #else
 #define UPSCALE(x)  ((x) << (BITS_IN_JSAMPLE - 8))
 #endif
-    cmap[CM_RED][i]   = (JSAMPLE)UPSCALE(ReadByte(sinfo));
-    cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo));
-    cmap[CM_BLUE][i]  = (JSAMPLE)UPSCALE(ReadByte(sinfo));
+    cmap[CM_RED][i]   = (_JSAMPLE)UPSCALE(ReadByte(sinfo));
+    cmap[CM_GREEN][i] = (_JSAMPLE)UPSCALE(ReadByte(sinfo));
+    cmap[CM_BLUE][i]  = (_JSAMPLE)UPSCALE(ReadByte(sinfo));
     if (cmap[CM_RED][i] != cmap[CM_GREEN][i] ||
         cmap[CM_GREEN][i] != cmap[CM_BLUE][i])
       gray = 0;
@@ -427,7 +429,7 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
     TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);
 
   /* Allocate space to store the colormap */
-  source->colormap = (*cinfo->mem->alloc_sarray)
+  source->colormap = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
     ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)MAXCOLORMAPSIZE,
      (JDIMENSION)NUMCOLORS);
   colormaplen = 0;              /* indicate initialization */
@@ -530,7 +532,7 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   }
 
   /* Create compressor input buffer. */
-  source->pub.buffer = (*cinfo->mem->alloc_sarray)
+  source->pub._buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
     ((j_common_ptr)cinfo, JPOOL_IMAGE,
      (JDIMENSION)width * cinfo->input_components, (JDIMENSION)1);
   source->pub.buffer_height = 1;
@@ -539,7 +541,7 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   for (c = colormaplen; c < source->clear_code; c++) {
     source->colormap[CM_RED][c]   =
     source->colormap[CM_GREEN][c] =
-    source->colormap[CM_BLUE][c]  = CENTERJSAMPLE;
+    source->colormap[CM_BLUE][c]  = _CENTERJSAMPLE;
   }
 
   /* Return info about the image. */
@@ -562,11 +564,11 @@ get_pixel_rows(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   gif_source_ptr source = (gif_source_ptr)sinfo;
   register int c;
-  register JSAMPROW ptr;
+  register _JSAMPROW ptr;
   register JDIMENSION col;
-  register JSAMPARRAY colormap = source->colormap;
+  register _JSAMPARRAY colormap = source->colormap;
 
-  ptr = source->pub.buffer[0];
+  ptr = source->pub._buffer[0];
   if (cinfo->in_color_space == JCS_GRAYSCALE) {
     for (col = cinfo->image_width; col > 0; col--) {
       c = LZWReadByte(source);
@@ -594,7 +596,7 @@ METHODDEF(JDIMENSION)
 load_interlaced_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   gif_source_ptr source = (gif_source_ptr)sinfo;
-  register JSAMPROW sptr;
+  register _JSAMPROW sptr;
   register JDIMENSION col;
   JDIMENSION row;
   cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
@@ -606,11 +608,11 @@ load_interlaced_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
       progress->pub.pass_limit = (long)cinfo->image_height;
       (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
     }
-    sptr = *(*cinfo->mem->access_virt_sarray)
+    sptr = *(_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
       ((j_common_ptr)cinfo, source->interlaced_image, row, (JDIMENSION)1,
        TRUE);
     for (col = cinfo->image_width; col > 0; col--) {
-      *sptr++ = (JSAMPLE)LZWReadByte(source);
+      *sptr++ = (_JSAMPLE)LZWReadByte(source);
     }
   }
   if (progress != NULL)
@@ -639,9 +641,9 @@ get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   gif_source_ptr source = (gif_source_ptr)sinfo;
   register int c;
-  register JSAMPROW sptr, ptr;
+  register _JSAMPROW sptr, ptr;
   register JDIMENSION col;
-  register JSAMPARRAY colormap = source->colormap;
+  register _JSAMPARRAY colormap = source->colormap;
   JDIMENSION irow;
 
   /* Figure out which row of interlaced image is needed, and access it. */
@@ -659,11 +661,11 @@ get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   default:                      /* fourth-pass row */
     irow = (source->cur_row_number >> 1) + source->pass4_offset;
   }
-  sptr = *(*cinfo->mem->access_virt_sarray)
+  sptr = *(_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
     ((j_common_ptr)cinfo, source->interlaced_image, irow, (JDIMENSION)1,
      FALSE);
   /* Scan the row, expand colormap, and output */
-  ptr = source->pub.buffer[0];
+  ptr = source->pub._buffer[0];
   if (cinfo->in_color_space == JCS_GRAYSCALE) {
     for (col = cinfo->image_width; col > 0; col--) {
       c = *sptr++;
@@ -698,10 +700,13 @@ finish_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  */
 
 GLOBAL(cjpeg_source_ptr)
-jinit_read_gif(j_compress_ptr cinfo)
+_jinit_read_gif(j_compress_ptr cinfo)
 {
   gif_source_ptr source;
 
+  if (cinfo->data_precision != BITS_IN_JSAMPLE)
+    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,
@@ -717,4 +722,5 @@ jinit_read_gif(j_compress_ptr cinfo)
   return (cjpeg_source_ptr)source;
 }
 
-#endif /* GIF_SUPPORTED */
+#endif /* defined(GIF_SUPPORTED) &&
+          (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)) */
diff --git a/rdppm.c b/rdppm.c
index 294749a..5705806 100644 (file)
--- a/rdppm.c
+++ b/rdppm.c
@@ -5,7 +5,7 @@
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * Modified 2009 by Bill Allombert, Guido Vollbeding.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2015-2017, 2020-2022, D. R. Commander.
+ * Copyright (C) 2015-2017, 2020-2023, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README.ijg
  * file.
  *
@@ -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 @@ typedef struct {
 
   /* 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,10 @@ read_pbm_integer(j_compress_ptr cinfo, FILE *infile, unsigned int maxval)
  * 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 the size of _JSAMPLE.
  *
  * 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, which is the normal case for 8-bit data.
  */
 
 
@@ -137,12 +138,12 @@ get_text_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   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 +166,8 @@ get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   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 +176,17 @@ get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   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 == _MAXJSAMPLE) {
     if (aindex >= 0)
-      GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
-                         ptr[aindex] = 0xFF;)
+      GRAY_RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
+                         ptr[aindex] = _MAXJSAMPLE;)
     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] = 0xFF;)
+                         ptr[aindex] = _MAXJSAMPLE;)
     else
       GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
   }
@@ -200,21 +201,21 @@ get_text_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   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 == _MAXJSAMPLE) {
     for (col = cinfo->image_width; col > 0; col--) {
-      JSAMPLE gray = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
+      _JSAMPLE gray = (_JSAMPLE)read_pbm_integer(cinfo, infile, maxval);
       rgb_to_cmyk(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)];
+      _JSAMPLE gray = rescale[read_pbm_integer(cinfo, infile, maxval)];
       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
       ptr += 4;
     }
@@ -239,8 +240,8 @@ get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   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 +250,17 @@ get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   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 == _MAXJSAMPLE) {
     if (aindex >= 0)
-      RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
-                    ptr[aindex] = 0xFF;)
+      RGB_READ_LOOP((_JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
+                    ptr[aindex] = _MAXJSAMPLE;)
     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] = 0xFF;)
+                    ptr[aindex] = _MAXJSAMPLE;)
     else
       RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
   }
@@ -274,25 +275,25 @@ get_text_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 {
   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 == _MAXJSAMPLE) {
     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);
+      _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);
       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)];
+      _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);
       ptr += 4;
     }
@@ -306,14 +307,14 @@ get_scaled_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 /* 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 +329,9 @@ get_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    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 +342,17 @@ get_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 
   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 == _MAXJSAMPLE) {
     if (aindex >= 0)
-      GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+      GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = _MAXJSAMPLE;)
     else
       GRAY_RGB_READ_LOOP(*bufferptr++, {})
   } else {
     if (aindex >= 0)
-      GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+      GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],
+                         ptr[aindex] = _MAXJSAMPLE;)
     else
       GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
   }
@@ -364,25 +366,25 @@ get_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    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 == _MAXJSAMPLE) {
     for (col = cinfo->image_width; col > 0; col--) {
-      JSAMPLE gray = *bufferptr++;
+      _JSAMPLE gray = *bufferptr++;
       rgb_to_cmyk(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++)];
+      _JSAMPLE gray = rescale[UCH(*bufferptr++)];
       rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3);
       ptr += 4;
     }
@@ -396,9 +398,9 @@ get_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 /* 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 +411,16 @@ get_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 
   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 == _MAXJSAMPLE) {
     if (aindex >= 0)
-      RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+      RGB_READ_LOOP(*bufferptr++, ptr[aindex] = _MAXJSAMPLE;)
     else
       RGB_READ_LOOP(*bufferptr++, {})
   } else {
     if (aindex >= 0)
-      RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+      RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = _MAXJSAMPLE;)
     else
       RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
   }
@@ -432,29 +434,29 @@ get_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    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 == _MAXJSAMPLE) {
     for (col = cinfo->image_width; col > 0; col--) {
-      JSAMPLE r = *bufferptr++;
-      JSAMPLE g = *bufferptr++;
-      JSAMPLE b = *bufferptr++;
+      _JSAMPLE r = *bufferptr++;
+      _JSAMPLE g = *bufferptr++;
+      _JSAMPLE b = *bufferptr++;
       rgb_to_cmyk(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++)];
+      _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);
       ptr += 4;
     }
@@ -465,8 +467,8 @@ get_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 
 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.
+ * In this case we just read right into the _JSAMPLE buffer!
  * Note that same code works for PPM and PGM files.
  */
 {
@@ -483,15 +485,15 @@ get_word_gray_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;
 
   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 +508,77 @@ get_word_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 
 
 METHODDEF(JDIMENSION)
+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 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;
+    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] = _MAXJSAMPLE;
+    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(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 _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 +589,7 @@ get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
 
   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;
@@ -543,13 +609,50 @@ get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
       ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
     ptr[bindex] = rescale[temp];
     if (aindex >= 0)
-      ptr[aindex] = 0xFF;
+      ptr[aindex] = _MAXJSAMPLE;
     ptr += ps;
   }
   return 1;
 }
 
 
+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(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.
  */
@@ -639,9 +742,13 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
     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) &&
                cinfo->in_color_space == JCS_GRAYSCALE) {
       source->pub.get_pixel_rows = get_raw_row;
       use_raw_buffer = TRUE;
@@ -665,9 +772,11 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
     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) &&
 #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 +820,13 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
   /* 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,16 +837,16 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
     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) /
+      source->rescale[val] = (_JSAMPLE)((val * _MAXJSAMPLE + half_maxval) /
                                         maxval);
     }
   }
@@ -760,10 +869,13 @@ finish_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
  */
 
 GLOBAL(cjpeg_source_ptr)
-jinit_read_ppm(j_compress_ptr cinfo)
+_jinit_read_ppm(j_compress_ptr cinfo)
 {
   ppm_source_ptr source;
 
+  if (cinfo->data_precision != BITS_IN_JSAMPLE)
+    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,
@@ -778,4 +890,5 @@ jinit_read_ppm(j_compress_ptr cinfo)
   return (cjpeg_source_ptr)source;
 }
 
-#endif /* PPM_SUPPORTED */
+#endif /* defined(PPM_SUPPORTED) &&
+          (BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)) */
index 3ed7eb3..dae0b58 100644 (file)
--- a/rdtarga.c
+++ b/rdtarga.c
@@ -490,6 +490,9 @@ jinit_read_targa(j_compress_ptr cinfo)
 {
   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,
index 446ce46..a71d15c 100644 (file)
@@ -2,4 +2,4 @@ libjpeg-turbo is a JPEG image codec that uses SIMD instructions to accelerate ba
 
 libjpeg-turbo implements both the traditional libjpeg API as well as the less powerful but more straightforward TurboJPEG API.  libjpeg-turbo also features colorspace extensions that allow it to compress from/decompress to 32-bit and big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java interface.
 
-libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated derivative of libjpeg v6b developed by Miyasaka Masaru.  The TigerVNC and VirtualGL projects made numerous enhancements to the codec in 2009, and in early 2010, libjpeg-turbo spun off into an independent project, with the goal of making high-speed JPEG compression/decompression technology available to a broader range of users and developers.
+libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated derivative of libjpeg v6b developed by Miyasaka Masaru.  The TigerVNC and VirtualGL projects made numerous enhancements to the codec in 2009, and in early 2010, libjpeg-turbo spun off into an independent project, with the goal of making high-speed JPEG compression/decompression technology available to a broader range of users and developers.  libjpeg-turbo is an ISO/IEC and ITU-T reference implementation of the JPEG standard.
index 72bceec..2c2ae38 100644 (file)
@@ -28,4 +28,5 @@ Description: A SIMD-accelerated JPEG codec that provides both the libjpeg and Tu
  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.
index 65db63d..0fdd2ed 100644 (file)
@@ -90,7 +90,7 @@ Section "@CMAKE_PROJECT_NAME@ SDK for @INST_PLATFORM@ (required)"
        File "@CMAKE_CURRENT_SOURCE_DIR@\README.ijg"
        File "@CMAKE_CURRENT_SOURCE_DIR@\README.md"
        File "@CMAKE_CURRENT_SOURCE_DIR@\LICENSE.md"
-       File "@CMAKE_CURRENT_SOURCE_DIR@\example.txt"
+       File "@CMAKE_CURRENT_SOURCE_DIR@\example.c"
        File "@CMAKE_CURRENT_SOURCE_DIR@\libjpeg.txt"
        File "@CMAKE_CURRENT_SOURCE_DIR@\structure.txt"
        File "@CMAKE_CURRENT_SOURCE_DIR@\usage.txt"
@@ -168,7 +168,7 @@ Section "Uninstall"
        Delete $INSTDIR\doc\README.ijg
        Delete $INSTDIR\doc\README.md
        Delete $INSTDIR\doc\LICENSE.md
-       Delete $INSTDIR\doc\example.txt
+       Delete $INSTDIR\doc\example.c
        Delete $INSTDIR\doc\libjpeg.txt
        Delete $INSTDIR\doc\structure.txt
        Delete $INSTDIR\doc\usage.txt
index 4207024..24872db 100644 (file)
@@ -77,7 +77,8 @@ derivative of libjpeg v6b developed by Miyasaka Masaru.  The TigerVNC and
 VirtualGL projects made numerous enhancements to the codec in 2009, and in
 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.
 
 #-->%prep
 #-->%setup -q -n @CMAKE_PROJECT_NAME@-%{version}
@@ -99,11 +100,10 @@ broader range of users and developers.
 #-->  -DSO_MINOR_VERSION=@SO_MINOR_VERSION@ \
 #-->  -DJPEG_LIB_VERSION=@JPEG_LIB_VERSION@ \
 #-->  -DREQUIRE_SIMD=@REQUIRE_SIMD@ \
-#-->  -DWITH_12BIT=@WITH_12BIT@ -DWITH_ARITH_DEC=@WITH_ARITH_DEC@ \
-#-->  -DWITH_ARITH_ENC=@WITH_ARITH_ENC@ -DWITH_JAVA=@WITH_JAVA@ \
+#-->  -DWITH_ARITH_DEC=@WITH_ARITH_DEC@ -DWITH_ARITH_ENC=@WITH_ARITH_ENC@ \
+#-->  -DWITH_JAVA=@WITH_JAVA@ \
 #-->  -DWITH_JPEG7=@WITH_JPEG7@ -DWITH_JPEG8=@WITH_JPEG8@ \
-#-->  -DWITH_MEM_SRCDST=@WITH_MEM_SRCDST@ -DWITH_SIMD=@WITH_SIMD@ \
-#-->  -DWITH_TURBOJPEG=@WITH_TURBOJPEG@ .
+#-->  -DWITH_SIMD=@WITH_SIMD@ -DWITH_TURBOJPEG=@WITH_TURBOJPEG@ .
 #-->make DESTDIR=$RPM_BUILD_ROOT
 
 %install
index aea0b9d..8e94256 100644 (file)
@@ -29,19 +29,15 @@ if(WITH_SIMD AND (MSVC_IDE OR XCODE))
 endif()
 
 if(WIN32)
-  if(WITH_MEM_SRCDST)
-    set(DEFFILE ../win/jpeg${SO_MAJOR_VERSION}-memsrcdst.def)
-  else()
-    set(DEFFILE ../win/jpeg${SO_MAJOR_VERSION}.def)
-  endif()
+  set(DEFFILE ../win/jpeg${SO_MAJOR_VERSION}.def)
 endif()
 if(MSVC)
   configure_file(${CMAKE_SOURCE_DIR}/win/jpeg.rc.in
     ${CMAKE_BINARY_DIR}/win/jpeg.rc)
   set(JPEG_SRCS ${JPEG_SRCS} ${CMAKE_BINARY_DIR}/win/jpeg.rc)
 endif()
-add_library(jpeg SHARED ${JPEG_SRCS} ${DEFFILE} $<TARGET_OBJECTS:simd>
-  ${SIMD_OBJS})
+add_library(jpeg SHARED ${JPEG_SRCS} ${DEFFILE} ${SIMD_TARGET_OBJECTS}
+  ${SIMD_OBJS} $<TARGET_OBJECTS:jpeg12> $<TARGET_OBJECTS:jpeg16>)
 
 set_target_properties(jpeg PROPERTIES SOVERSION ${SO_MAJOR_VERSION}
   VERSION ${SO_MAJOR_VERSION}.${SO_AGE}.${SO_MINOR_VERSION})
@@ -60,7 +56,8 @@ if(MSVC)
   set_target_properties(jpeg PROPERTIES
     RUNTIME_OUTPUT_NAME jpeg${SO_MAJOR_VERSION})
   # The jsimd_*.c file is built using /MT, so this prevents a linker warning.
-  set_target_properties(jpeg PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD")
+  set_target_properties(jpeg PROPERTIES LINK_FLAGS
+    "/NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD")
 elseif(MINGW)
   set_target_properties(jpeg PROPERTIES SUFFIX -${SO_MAJOR_VERSION}.dll)
 endif()
@@ -68,28 +65,44 @@ endif()
 if(WIN32)
   set(USE_SETMODE "-DUSE_SETMODE")
 endif()
-if(WITH_12BIT)
-  set(COMPILE_FLAGS "-DGIF_SUPPORTED -DPPM_SUPPORTED ${USE_SETMODE}")
-else()
-  set(COMPILE_FLAGS "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED ${USE_SETMODE}")
-  set(CJPEG_BMP_SOURCES ../rdbmp.c ../rdtarga.c)
-  set(DJPEG_BMP_SOURCES ../wrbmp.c ../wrtarga.c)
-endif()
+set(CDJPEG_COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED ${USE_SETMODE}")
 
-add_executable(cjpeg ../cjpeg.c ../cdjpeg.c ../rdgif.c ../rdppm.c
-  ../rdswitch.c ${CJPEG_BMP_SOURCES})
-set_property(TARGET cjpeg PROPERTY COMPILE_FLAGS ${COMPILE_FLAGS})
+# Compile a separate version of these source files with 12-bit and 16-bit data
+# precision.
+add_library(cjpeg12 OBJECT ../rdgif.c ../rdppm.c)
+set_property(TARGET cjpeg12 PROPERTY COMPILE_FLAGS
+  "-DBITS_IN_JSAMPLE=12 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+add_library(cjpeg16 OBJECT ../rdgif.c ../rdppm.c)
+set_property(TARGET cjpeg16 PROPERTY COMPILE_FLAGS
+  "-DBITS_IN_JSAMPLE=16 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+add_executable(cjpeg ../cjpeg.c ../cdjpeg.c ../rdbmp.c ../rdgif.c ../rdppm.c
+  ../rdswitch.c ../rdtarga.c $<TARGET_OBJECTS:cjpeg12>
+  $<TARGET_OBJECTS:cjpeg16>)
+set_property(TARGET cjpeg PROPERTY COMPILE_FLAGS ${CDJPEG_COMPILE_FLAGS})
 target_link_libraries(cjpeg jpeg)
 
+# Compile a separate version of these source files with 12-bit and 16-bit data
+# precision.
+add_library(djpeg12 OBJECT ../rdcolmap.c ../wrgif.c ../wrppm.c)
+set_property(TARGET djpeg12 PROPERTY COMPILE_FLAGS
+  "-DBITS_IN_JSAMPLE=12 -DGIF_SUPPORTED -DPPM_SUPPORTED")
+add_library(djpeg16 OBJECT ../wrppm.c)
+set_property(TARGET djpeg16 PROPERTY COMPILE_FLAGS
+  "-DBITS_IN_JSAMPLE=16 -DPPM_SUPPORTED")
 add_executable(djpeg ../djpeg.c ../cdjpeg.c ../rdcolmap.c ../rdswitch.c
-  ../wrgif.c ../wrppm.c ${DJPEG_BMP_SOURCES})
-set_property(TARGET djpeg PROPERTY COMPILE_FLAGS ${COMPILE_FLAGS})
+  ../wrbmp.c ../wrgif.c ../wrppm.c ../wrtarga.c $<TARGET_OBJECTS:djpeg12>
+  $<TARGET_OBJECTS:djpeg16>)
+set_property(TARGET djpeg PROPERTY COMPILE_FLAGS ${CDJPEG_COMPILE_FLAGS})
 target_link_libraries(djpeg jpeg)
 
 add_executable(jpegtran ../jpegtran.c ../cdjpeg.c ../rdswitch.c ../transupp.c)
 target_link_libraries(jpegtran jpeg)
 set_property(TARGET jpegtran PROPERTY COMPILE_FLAGS "${USE_SETMODE}")
 
+add_executable(example ../example.c)
+target_link_libraries(example jpeg)
+
 add_executable(jcstest ../jcstest.c)
 target_link_libraries(jcstest jpeg)
 
index a657196..b06a6c3 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2019, Google LLC.
  * Copyright (C) 2020, Arm Limited.
  *
@@ -32,8 +32,8 @@
 #include <unistd.h>
 #endif
 
-static unsigned int simd_support = ~0;
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_huffman = 1;
 
 #if !defined(__ARM_NEON__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
 
@@ -101,8 +101,6 @@ parse_proc_cpuinfo(int bufsize)
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -966,7 +964,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
   jsimd_encode_mcu_AC_first_prepare_neon(block, jpeg_natural_order_start,
                                          Sl, Al, values, zerobits);
@@ -991,7 +989,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return jsimd_encode_mcu_AC_refine_prepare_neon(block,
                                                  jpeg_natural_order_start, Sl,
index 41c06d3..358e159 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2020, Arm Limited.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
@@ -23,7 +23,6 @@
 #include "../../../jdct.h"
 #include "../../../jsimddct.h"
 #include "../../jsimd.h"
-#include "jconfigint.h"
 
 #include <ctype.h>
 
 #define JSIMD_FASTST3  2
 #define JSIMD_FASTTBL  4
 
-static unsigned int simd_support = ~0;
-static unsigned int simd_huffman = 1;
-static unsigned int simd_features = JSIMD_FASTLD3 | JSIMD_FASTST3 |
-                                    JSIMD_FASTTBL;
+static THREAD_LOCAL unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_features = JSIMD_FASTLD3 |
+                                                 JSIMD_FASTST3 | JSIMD_FASTTBL;
 
 #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
 
@@ -109,8 +108,6 @@ parse_proc_cpuinfo(int bufsize)
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 
 /*
@@ -1021,7 +1018,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
   jsimd_encode_mcu_AC_first_prepare_neon(block, jpeg_natural_order_start,
                                          Sl, Al, values, zerobits);
@@ -1048,7 +1045,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return jsimd_encode_mcu_AC_refine_prepare_neon(block,
                                                  jpeg_natural_order_start,
index b91c5db..51db3c5 100644 (file)
@@ -2,6 +2,8 @@
  * jcphuff-neon.c - prepare data for progressive Huffman encoding (Arm Neon)
  *
  * Copyright (C) 2020-2021, Arm Limited.  All Rights Reserved.
+ * Copyright (C) 2022, Matthieu Darbois.  All Rights Reserved.
+ * Copyright (C) 2022, D. R. Commander.  All Rights Reserved.
  *
  * This software is provided 'as-is', without any express or implied
  * warranty.  In no event will the authors be held liable for any damages
@@ -21,7 +23,6 @@
  */
 
 #define JPEG_INTERNALS
-#include "jconfigint.h"
 #include "../../jinclude.h"
 #include "../../jpeglib.h"
 #include "../../jsimd.h"
 
 void jsimd_encode_mcu_AC_first_prepare_neon
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *values, size_t *zerobits)
+   UJCOEF *values, size_t *zerobits)
 {
-  JCOEF *values_ptr = values;
-  JCOEF *diff_values_ptr = values + DCTSIZE2;
+  UJCOEF *values_ptr = values;
+  UJCOEF *diff_values_ptr = values + DCTSIZE2;
 
   /* Rows of coefficients to zero (since they haven't been processed) */
   int i, rows_to_zero = 8;
@@ -68,23 +69,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
     coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[15], coefs2, 7);
 
     /* Isolate sign of coefficients. */
-    int16x8_t sign_coefs1 = vshrq_n_s16(coefs1, 15);
-    int16x8_t sign_coefs2 = vshrq_n_s16(coefs2, 15);
+    uint16x8_t sign_coefs1 = vreinterpretq_u16_s16(vshrq_n_s16(coefs1, 15));
+    uint16x8_t sign_coefs2 = vreinterpretq_u16_s16(vshrq_n_s16(coefs2, 15));
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs1 = vabsq_s16(coefs1);
-    int16x8_t abs_coefs2 = vabsq_s16(coefs2);
-    coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
-    coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
+    uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+    uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+    abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+    abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
 
     /* Compute diff values. */
-    int16x8_t diff1 = veorq_s16(coefs1, sign_coefs1);
-    int16x8_t diff2 = veorq_s16(coefs2, sign_coefs2);
+    uint16x8_t diff1 = veorq_u16(abs_coefs1, sign_coefs1);
+    uint16x8_t diff2 = veorq_u16(abs_coefs2, sign_coefs2);
 
     /* Store transformed coefficients and diff values. */
-    vst1q_s16(values_ptr, coefs1);
-    vst1q_s16(values_ptr + DCTSIZE, coefs2);
-    vst1q_s16(diff_values_ptr, diff1);
-    vst1q_s16(diff_values_ptr + DCTSIZE, diff2);
+    vst1q_u16(values_ptr, abs_coefs1);
+    vst1q_u16(values_ptr + DCTSIZE, abs_coefs2);
+    vst1q_u16(diff_values_ptr, diff1);
+    vst1q_u16(diff_values_ptr + DCTSIZE, diff2);
     values_ptr += 16;
     diff_values_ptr += 16;
     jpeg_natural_order_start += 16;
@@ -130,23 +131,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
     }
 
     /* Isolate sign of coefficients. */
-    int16x8_t sign_coefs1 = vshrq_n_s16(coefs1, 15);
-    int16x8_t sign_coefs2 = vshrq_n_s16(coefs2, 15);
+    uint16x8_t sign_coefs1 = vreinterpretq_u16_s16(vshrq_n_s16(coefs1, 15));
+    uint16x8_t sign_coefs2 = vreinterpretq_u16_s16(vshrq_n_s16(coefs2, 15));
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs1 = vabsq_s16(coefs1);
-    int16x8_t abs_coefs2 = vabsq_s16(coefs2);
-    coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
-    coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
+    uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+    uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+    abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+    abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
 
     /* Compute diff values. */
-    int16x8_t diff1 = veorq_s16(coefs1, sign_coefs1);
-    int16x8_t diff2 = veorq_s16(coefs2, sign_coefs2);
+    uint16x8_t diff1 = veorq_u16(abs_coefs1, sign_coefs1);
+    uint16x8_t diff2 = veorq_u16(abs_coefs2, sign_coefs2);
 
     /* Store transformed coefficients and diff values. */
-    vst1q_s16(values_ptr, coefs1);
-    vst1q_s16(values_ptr + DCTSIZE, coefs2);
-    vst1q_s16(diff_values_ptr, diff1);
-    vst1q_s16(diff_values_ptr + DCTSIZE, diff2);
+    vst1q_u16(values_ptr, abs_coefs1);
+    vst1q_u16(values_ptr + DCTSIZE, abs_coefs2);
+    vst1q_u16(diff_values_ptr, diff1);
+    vst1q_u16(diff_values_ptr + DCTSIZE, diff2);
     values_ptr += 16;
     diff_values_ptr += 16;
     rows_to_zero -= 2;
@@ -184,17 +185,17 @@ void jsimd_encode_mcu_AC_first_prepare_neon
     }
 
     /* Isolate sign of coefficients. */
-    int16x8_t sign_coefs = vshrq_n_s16(coefs, 15);
+    uint16x8_t sign_coefs = vreinterpretq_u16_s16(vshrq_n_s16(coefs, 15));
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs = vabsq_s16(coefs);
-    coefs = vshlq_s16(abs_coefs, vdupq_n_s16(-Al));
+    uint16x8_t abs_coefs = vreinterpretq_u16_s16(vabsq_s16(coefs));
+    abs_coefs = vshlq_u16(abs_coefs, vdupq_n_s16(-Al));
 
     /* Compute diff values. */
-    int16x8_t diff = veorq_s16(coefs, sign_coefs);
+    uint16x8_t diff = veorq_u16(abs_coefs, sign_coefs);
 
     /* Store transformed coefficients and diff values. */
-    vst1q_s16(values_ptr, coefs);
-    vst1q_s16(diff_values_ptr, diff);
+    vst1q_u16(values_ptr, abs_coefs);
+    vst1q_u16(diff_values_ptr, diff);
     values_ptr += 8;
     diff_values_ptr += 8;
     rows_to_zero--;
@@ -202,8 +203,8 @@ void jsimd_encode_mcu_AC_first_prepare_neon
 
   /* Zero remaining memory in the values and diff_values blocks. */
   for (i = 0; i < rows_to_zero; i++) {
-    vst1q_s16(values_ptr, vdupq_n_s16(0));
-    vst1q_s16(diff_values_ptr, vdupq_n_s16(0));
+    vst1q_u16(values_ptr, vdupq_n_u16(0));
+    vst1q_u16(diff_values_ptr, vdupq_n_u16(0));
     values_ptr += 8;
     diff_values_ptr += 8;
   }
@@ -211,23 +212,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
   /* Construct zerobits bitmap.  A set bit means that the corresponding
    * coefficient != 0.
    */
-  int16x8_t row0 = vld1q_s16(values + 0 * DCTSIZE);
-  int16x8_t row1 = vld1q_s16(values + 1 * DCTSIZE);
-  int16x8_t row2 = vld1q_s16(values + 2 * DCTSIZE);
-  int16x8_t row3 = vld1q_s16(values + 3 * DCTSIZE);
-  int16x8_t row4 = vld1q_s16(values + 4 * DCTSIZE);
-  int16x8_t row5 = vld1q_s16(values + 5 * DCTSIZE);
-  int16x8_t row6 = vld1q_s16(values + 6 * DCTSIZE);
-  int16x8_t row7 = vld1q_s16(values + 7 * DCTSIZE);
-
-  uint8x8_t row0_eq0 = vmovn_u16(vceqq_s16(row0, vdupq_n_s16(0)));
-  uint8x8_t row1_eq0 = vmovn_u16(vceqq_s16(row1, vdupq_n_s16(0)));
-  uint8x8_t row2_eq0 = vmovn_u16(vceqq_s16(row2, vdupq_n_s16(0)));
-  uint8x8_t row3_eq0 = vmovn_u16(vceqq_s16(row3, vdupq_n_s16(0)));
-  uint8x8_t row4_eq0 = vmovn_u16(vceqq_s16(row4, vdupq_n_s16(0)));
-  uint8x8_t row5_eq0 = vmovn_u16(vceqq_s16(row5, vdupq_n_s16(0)));
-  uint8x8_t row6_eq0 = vmovn_u16(vceqq_s16(row6, vdupq_n_s16(0)));
-  uint8x8_t row7_eq0 = vmovn_u16(vceqq_s16(row7, vdupq_n_s16(0)));
+  uint16x8_t row0 = vld1q_u16(values + 0 * DCTSIZE);
+  uint16x8_t row1 = vld1q_u16(values + 1 * DCTSIZE);
+  uint16x8_t row2 = vld1q_u16(values + 2 * DCTSIZE);
+  uint16x8_t row3 = vld1q_u16(values + 3 * DCTSIZE);
+  uint16x8_t row4 = vld1q_u16(values + 4 * DCTSIZE);
+  uint16x8_t row5 = vld1q_u16(values + 5 * DCTSIZE);
+  uint16x8_t row6 = vld1q_u16(values + 6 * DCTSIZE);
+  uint16x8_t row7 = vld1q_u16(values + 7 * DCTSIZE);
+
+  uint8x8_t row0_eq0 = vmovn_u16(vceqq_u16(row0, vdupq_n_u16(0)));
+  uint8x8_t row1_eq0 = vmovn_u16(vceqq_u16(row1, vdupq_n_u16(0)));
+  uint8x8_t row2_eq0 = vmovn_u16(vceqq_u16(row2, vdupq_n_u16(0)));
+  uint8x8_t row3_eq0 = vmovn_u16(vceqq_u16(row3, vdupq_n_u16(0)));
+  uint8x8_t row4_eq0 = vmovn_u16(vceqq_u16(row4, vdupq_n_u16(0)));
+  uint8x8_t row5_eq0 = vmovn_u16(vceqq_u16(row5, vdupq_n_u16(0)));
+  uint8x8_t row6_eq0 = vmovn_u16(vceqq_u16(row6, vdupq_n_u16(0)));
+  uint8x8_t row7_eq0 = vmovn_u16(vceqq_u16(row7, vdupq_n_u16(0)));
 
   /* { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } */
   const uint8x8_t bitmap_mask =
@@ -274,7 +275,7 @@ void jsimd_encode_mcu_AC_first_prepare_neon
 
 int jsimd_encode_mcu_AC_refine_prepare_neon
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *absvalues, size_t *bits)
+   UJCOEF *absvalues, size_t *bits)
 {
   /* Temporary storage buffers for data used to compute the signbits bitmap and
    * the end-of-block (EOB) position
@@ -282,7 +283,7 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
   uint8_t coef_sign_bits[64];
   uint8_t coef_eq1_bits[64];
 
-  JCOEF *absvalues_ptr = absvalues;
+  UJCOEF *absvalues_ptr = absvalues;
   uint8_t *coef_sign_bits_ptr = coef_sign_bits;
   uint8_t *eq1_bits_ptr = coef_eq1_bits;
 
@@ -316,18 +317,18 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
     vst1_u8(coef_sign_bits_ptr + DCTSIZE, sign_coefs2);
 
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs1 = vabsq_s16(coefs1);
-    int16x8_t abs_coefs2 = vabsq_s16(coefs2);
-    coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
-    coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
-    vst1q_s16(absvalues_ptr, coefs1);
-    vst1q_s16(absvalues_ptr + DCTSIZE, coefs2);
+    uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+    uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+    abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+    abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
+    vst1q_u16(absvalues_ptr, abs_coefs1);
+    vst1q_u16(absvalues_ptr + DCTSIZE, abs_coefs2);
 
     /* Test whether transformed coefficient values == 1 (used to find EOB
      * position.)
      */
-    uint8x8_t coefs_eq11 = vmovn_u16(vceqq_s16(coefs1, vdupq_n_s16(1)));
-    uint8x8_t coefs_eq12 = vmovn_u16(vceqq_s16(coefs2, vdupq_n_s16(1)));
+    uint8x8_t coefs_eq11 = vmovn_u16(vceqq_u16(abs_coefs1, vdupq_n_u16(1)));
+    uint8x8_t coefs_eq12 = vmovn_u16(vceqq_u16(abs_coefs2, vdupq_n_u16(1)));
     vst1_u8(eq1_bits_ptr, coefs_eq11);
     vst1_u8(eq1_bits_ptr + DCTSIZE, coefs_eq12);
 
@@ -385,18 +386,18 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
     vst1_u8(coef_sign_bits_ptr + DCTSIZE, sign_coefs2);
 
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs1 = vabsq_s16(coefs1);
-    int16x8_t abs_coefs2 = vabsq_s16(coefs2);
-    coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
-    coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
-    vst1q_s16(absvalues_ptr, coefs1);
-    vst1q_s16(absvalues_ptr + DCTSIZE, coefs2);
+    uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+    uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+    abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+    abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
+    vst1q_u16(absvalues_ptr, abs_coefs1);
+    vst1q_u16(absvalues_ptr + DCTSIZE, abs_coefs2);
 
     /* Test whether transformed coefficient values == 1 (used to find EOB
      * position.)
      */
-    uint8x8_t coefs_eq11 = vmovn_u16(vceqq_s16(coefs1, vdupq_n_s16(1)));
-    uint8x8_t coefs_eq12 = vmovn_u16(vceqq_s16(coefs2, vdupq_n_s16(1)));
+    uint8x8_t coefs_eq11 = vmovn_u16(vceqq_u16(abs_coefs1, vdupq_n_u16(1)));
+    uint8x8_t coefs_eq12 = vmovn_u16(vceqq_u16(abs_coefs2, vdupq_n_u16(1)));
     vst1_u8(eq1_bits_ptr, coefs_eq11);
     vst1_u8(eq1_bits_ptr + DCTSIZE, coefs_eq12);
 
@@ -444,14 +445,14 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
     vst1_u8(coef_sign_bits_ptr, sign_coefs);
 
     /* Compute absolute value of coefficients and apply point transform Al. */
-    int16x8_t abs_coefs = vabsq_s16(coefs);
-    coefs = vshlq_s16(abs_coefs, vdupq_n_s16(-Al));
-    vst1q_s16(absvalues_ptr, coefs);
+    uint16x8_t abs_coefs = vreinterpretq_u16_s16(vabsq_s16(coefs));
+    abs_coefs = vshlq_u16(abs_coefs, vdupq_n_s16(-Al));
+    vst1q_u16(absvalues_ptr, abs_coefs);
 
     /* Test whether transformed coefficient values == 1 (used to find EOB
      * position.)
      */
-    uint8x8_t coefs_eq1 = vmovn_u16(vceqq_s16(coefs, vdupq_n_s16(1)));
+    uint8x8_t coefs_eq1 = vmovn_u16(vceqq_u16(abs_coefs, vdupq_n_u16(1)));
     vst1_u8(eq1_bits_ptr, coefs_eq1);
 
     absvalues_ptr += 8;
@@ -462,7 +463,7 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
 
   /* Zero remaining memory in blocks. */
   for (i = 0; i < rows_to_zero; i++) {
-    vst1q_s16(absvalues_ptr, vdupq_n_s16(0));
+    vst1q_u16(absvalues_ptr, vdupq_n_u16(0));
     vst1_u8(coef_sign_bits_ptr, vdup_n_u8(0));
     vst1_u8(eq1_bits_ptr, vdup_n_u8(0));
     absvalues_ptr += 8;
@@ -471,23 +472,23 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
   }
 
   /* Construct zerobits bitmap. */
-  int16x8_t abs_row0 = vld1q_s16(absvalues + 0 * DCTSIZE);
-  int16x8_t abs_row1 = vld1q_s16(absvalues + 1 * DCTSIZE);
-  int16x8_t abs_row2 = vld1q_s16(absvalues + 2 * DCTSIZE);
-  int16x8_t abs_row3 = vld1q_s16(absvalues + 3 * DCTSIZE);
-  int16x8_t abs_row4 = vld1q_s16(absvalues + 4 * DCTSIZE);
-  int16x8_t abs_row5 = vld1q_s16(absvalues + 5 * DCTSIZE);
-  int16x8_t abs_row6 = vld1q_s16(absvalues + 6 * DCTSIZE);
-  int16x8_t abs_row7 = vld1q_s16(absvalues + 7 * DCTSIZE);
-
-  uint8x8_t abs_row0_eq0 = vmovn_u16(vceqq_s16(abs_row0, vdupq_n_s16(0)));
-  uint8x8_t abs_row1_eq0 = vmovn_u16(vceqq_s16(abs_row1, vdupq_n_s16(0)));
-  uint8x8_t abs_row2_eq0 = vmovn_u16(vceqq_s16(abs_row2, vdupq_n_s16(0)));
-  uint8x8_t abs_row3_eq0 = vmovn_u16(vceqq_s16(abs_row3, vdupq_n_s16(0)));
-  uint8x8_t abs_row4_eq0 = vmovn_u16(vceqq_s16(abs_row4, vdupq_n_s16(0)));
-  uint8x8_t abs_row5_eq0 = vmovn_u16(vceqq_s16(abs_row5, vdupq_n_s16(0)));
-  uint8x8_t abs_row6_eq0 = vmovn_u16(vceqq_s16(abs_row6, vdupq_n_s16(0)));
-  uint8x8_t abs_row7_eq0 = vmovn_u16(vceqq_s16(abs_row7, vdupq_n_s16(0)));
+  uint16x8_t abs_row0 = vld1q_u16(absvalues + 0 * DCTSIZE);
+  uint16x8_t abs_row1 = vld1q_u16(absvalues + 1 * DCTSIZE);
+  uint16x8_t abs_row2 = vld1q_u16(absvalues + 2 * DCTSIZE);
+  uint16x8_t abs_row3 = vld1q_u16(absvalues + 3 * DCTSIZE);
+  uint16x8_t abs_row4 = vld1q_u16(absvalues + 4 * DCTSIZE);
+  uint16x8_t abs_row5 = vld1q_u16(absvalues + 5 * DCTSIZE);
+  uint16x8_t abs_row6 = vld1q_u16(absvalues + 6 * DCTSIZE);
+  uint16x8_t abs_row7 = vld1q_u16(absvalues + 7 * DCTSIZE);
+
+  uint8x8_t abs_row0_eq0 = vmovn_u16(vceqq_u16(abs_row0, vdupq_n_u16(0)));
+  uint8x8_t abs_row1_eq0 = vmovn_u16(vceqq_u16(abs_row1, vdupq_n_u16(0)));
+  uint8x8_t abs_row2_eq0 = vmovn_u16(vceqq_u16(abs_row2, vdupq_n_u16(0)));
+  uint8x8_t abs_row3_eq0 = vmovn_u16(vceqq_u16(abs_row3, vdupq_n_u16(0)));
+  uint8x8_t abs_row4_eq0 = vmovn_u16(vceqq_u16(abs_row4, vdupq_n_u16(0)));
+  uint8x8_t abs_row5_eq0 = vmovn_u16(vceqq_u16(abs_row5, vdupq_n_u16(0)));
+  uint8x8_t abs_row6_eq0 = vmovn_u16(vceqq_u16(abs_row6, vdupq_n_u16(0)));
+  uint8x8_t abs_row7_eq0 = vmovn_u16(vceqq_u16(abs_row7, vdupq_n_u16(0)));
 
   /* { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } */
   const uint8x8_t bitmap_mask =
index ea4668f..28dbc57 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #define JPEG_INTERNALS
-#include "jconfigint.h"
 #include "../../jinclude.h"
 #include "../../jpeglib.h"
 #include "../../jsimd.h"
index e4f91fd..18fb9d8 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #define JPEG_INTERNALS
-#include "jconfigint.h"
 #include "../../jinclude.h"
 #include "../../jpeglib.h"
 #include "../../jsimd.h"
index 043b652..d25112e 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #define JPEG_INTERNALS
-#include "jconfigint.h"
 #include "../../jinclude.h"
 #include "../../jpeglib.h"
 #include "../../jsimd.h"
index 80bc821..b429b0a 100644 (file)
@@ -2,8 +2,8 @@
  * jsimd_i386.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -21,7 +21,6 @@
 #include "../../jdct.h"
 #include "../../jsimddct.h"
 #include "../jsimd.h"
-#include "jconfigint.h"
 
 /*
  * In the PIC cases, we have no guarantee that constants will keep
 #define IS_ALIGNED_SSE(ptr)  (IS_ALIGNED(ptr, 4)) /* 16 byte alignment */
 #define IS_ALIGNED_AVX(ptr)  (IS_ALIGNED(ptr, 5)) /* 32 byte alignment */
 
-static unsigned int simd_support = (unsigned int)(~0);
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = (unsigned int)(~0);
+static THREAD_LOCAL unsigned int simd_huffman = 1;
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -161,6 +158,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
   void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
   void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->in_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -220,6 +220,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
   void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
   void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->in_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -279,6 +282,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
   void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -382,6 +388,9 @@ GLOBAL(void)
 jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
                       JSAMPARRAY input_data, JSAMPARRAY output_data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
                                compptr->v_samp_factor,
@@ -402,6 +411,9 @@ GLOBAL(void)
 jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
                       JSAMPARRAY input_data, JSAMPARRAY output_data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
                                compptr->v_samp_factor,
@@ -464,6 +476,9 @@ GLOBAL(void)
 jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                     JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
                              input_data, output_data_ptr);
@@ -479,6 +494,9 @@ GLOBAL(void)
 jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                     JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
                              input_data, output_data_ptr);
@@ -540,6 +558,9 @@ GLOBAL(void)
 jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                           JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
                                    compptr->downsampled_width, input_data,
@@ -558,6 +579,9 @@ GLOBAL(void)
 jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                           JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
                                    compptr->downsampled_width, input_data,
@@ -626,6 +650,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
   void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -684,6 +711,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
   void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -788,6 +818,9 @@ GLOBAL(void)
 jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
                DCTELEM *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_convsamp_avx2(sample_data, start_col, workspace);
   else if (simd_support & JSIMD_SSE2)
@@ -800,6 +833,9 @@ GLOBAL(void)
 jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
                      FAST_FLOAT *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_SSE2)
     jsimd_convsamp_float_sse2(sample_data, start_col, workspace);
   else if (simd_support & JSIMD_SSE)
@@ -870,6 +906,9 @@ jsimd_can_fdct_float(void)
 GLOBAL(void)
 jsimd_fdct_islow(DCTELEM *data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_fdct_islow_avx2(data);
   else if (simd_support & JSIMD_SSE2)
@@ -881,6 +920,9 @@ jsimd_fdct_islow(DCTELEM *data)
 GLOBAL(void)
 jsimd_fdct_ifast(DCTELEM *data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_fdct_islow_sse2))
     jsimd_fdct_ifast_sse2(data);
   else
@@ -890,6 +932,9 @@ jsimd_fdct_ifast(DCTELEM *data)
 GLOBAL(void)
 jsimd_fdct_float(FAST_FLOAT *data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE) && IS_ALIGNED_SSE(jconst_fdct_float_sse))
     jsimd_fdct_float_sse(data);
   else if (simd_support & JSIMD_3DNOW)
@@ -945,6 +990,9 @@ jsimd_can_quantize_float(void)
 GLOBAL(void)
 jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_quantize_avx2(coef_block, divisors, workspace);
   else if (simd_support & JSIMD_SSE2)
@@ -957,6 +1005,9 @@ GLOBAL(void)
 jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
                      FAST_FLOAT *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_SSE2)
     jsimd_quantize_float_sse2(coef_block, divisors, workspace);
   else if (simd_support & JSIMD_SSE)
@@ -1020,6 +1071,9 @@ jsimd_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                JCOEFPTR coef_block, JSAMPARRAY output_buf,
                JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
     jsimd_idct_2x2_sse2(compptr->dct_table, coef_block, output_buf,
                         output_col);
@@ -1032,6 +1086,9 @@ jsimd_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                JCOEFPTR coef_block, JSAMPARRAY output_buf,
                JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
     jsimd_idct_4x4_sse2(compptr->dct_table, coef_block, output_buf,
                         output_col);
@@ -1126,6 +1183,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
                  JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
                           output_col);
@@ -1142,6 +1202,9 @@ jsimd_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
                  JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_ifast_sse2))
     jsimd_idct_ifast_sse2(compptr->dct_table, coef_block, output_buf,
                           output_col);
@@ -1155,6 +1218,9 @@ jsimd_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
                  JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_float_sse2))
     jsimd_idct_float_sse2(compptr->dct_table, coef_block, output_buf,
                           output_col);
@@ -1212,7 +1278,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
   jsimd_encode_mcu_AC_first_prepare_sse2(block, jpeg_natural_order_start,
                                          Sl, Al, values, zerobits);
@@ -1238,7 +1304,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return jsimd_encode_mcu_AC_refine_prepare_sse2(block,
                                                  jpeg_natural_order_start,
index 09127e0..4423278 100644 (file)
@@ -2,10 +2,10 @@
  * simd/jsimd.h
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014-2016, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2011, 2014-2016, 2018, 2020, 2022, D. R. Commander.
  * Copyright (C) 2013-2014, MIPS Technologies, Inc., California.
  * Copyright (C) 2014, Linaro Limited.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2016-2018, Loongson Technology Corporation Limited, BeiJing.
  * Copyright (C) 2020, Arm Limited.
  *
@@ -1243,19 +1243,19 @@ EXTERN(JOCTET *) jsimd_huff_encode_one_block_neon_slowtbl
 /* Progressive Huffman encoding */
 EXTERN(void) jsimd_encode_mcu_AC_first_prepare_sse2
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *values, size_t *zerobits);
+   UJCOEF *values, size_t *zerobits);
 
 EXTERN(void) jsimd_encode_mcu_AC_first_prepare_neon
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *values, size_t *zerobits);
+   UJCOEF *values, size_t *zerobits);
 
 EXTERN(int) jsimd_encode_mcu_AC_refine_prepare_sse2
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *absvalues, size_t *bits);
+   UJCOEF *absvalues, size_t *bits);
 
 EXTERN(int) jsimd_encode_mcu_AC_refine_prepare_neon
   (const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
-   JCOEF *absvalues, size_t *bits);
+   UJCOEF *absvalues, size_t *bits);
 
 /* TIZEN_PRODUCT_TV */
 EXTERN(void) jsimd_pick_color
index 36ea865..c6e789a 100644 (file)
@@ -2,9 +2,9 @@
  * jsimd_mips.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2020, 2022, D. R. Commander.
  * Copyright (C) 2013-2014, MIPS Technologies, Inc., California.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -25,7 +25,7 @@
 
 #include <ctype.h>
 
-static unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_support = ~0;
 
 #if !(defined(__mips_dsp) && (__mips_dsp_rev >= 2)) && defined(__linux__)
 
@@ -55,8 +55,6 @@ parse_proc_cpuinfo(const char *search_string)
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -1126,7 +1124,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
 }
 
@@ -1139,7 +1137,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return 0;
 }
index 2e626b2..917440b 100644 (file)
@@ -2,9 +2,9 @@
  * jsimd_mips64.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022, D. R. Commander.
  * Copyright (C) 2013-2014, MIPS Technologies, Inc., California.
- * Copyright (C) 2015, 2018, Matthieu Darbois.
+ * Copyright (C) 2015, 2018, 2022, Matthieu Darbois.
  * Copyright (C) 2016-2018, Loongson Technology Corporation Limited, BeiJing.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
@@ -26,7 +26,7 @@
 
 #include <ctype.h>
 
-static unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_support = ~0;
 
 #if defined(__linux__)
 
@@ -94,8 +94,6 @@ parse_proc_cpuinfo(int bufsize)
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -849,7 +847,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
 }
 
@@ -862,7 +860,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return 0;
 }
index e8d50b0..bebcb20 100644 (file)
@@ -5,6 +5,7 @@
 ; Copyright (C) 2010, 2016, 2018-2019, 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
 ;
@@ -397,11 +398,11 @@ const_base:
 %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
index 9a452a3..461f603 100644 (file)
@@ -2,8 +2,8 @@
  * jsimd_powerpc.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014-2016, 2018, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2014-2016, 2018, 2022, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -41,7 +41,7 @@
 #include <sys/auxv.h>
 #endif
 
-static unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_support = ~0;
 
 #if !defined(__ALTIVEC__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
 
@@ -109,8 +109,6 @@ parse_proc_cpuinfo(int bufsize)
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -867,7 +865,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
 }
 
@@ -880,7 +878,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return 0;
 }
index ffb527d..dd7ea39 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright (C) 2009, 2016, 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.
@@ -33,7 +34,7 @@
 ; 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
 
 EXTN(jsimd_rgb_ycc_convert_avx2):
     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)]
+    ; 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
 
@@ -549,8 +550,8 @@ EXTN(jsimd_rgb_ycc_convert_avx2):
     pop         rbx
     vzeroupper
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index af70ed6..bc1e817 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; Copyright (C) 2009, 2016, 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.
@@ -32,7 +33,7 @@
 ; 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
 
 EXTN(jsimd_rgb_ycc_convert_sse2):
     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)]
+    ; 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
 
@@ -474,8 +475,8 @@ EXTN(jsimd_rgb_ycc_convert_sse2):
 .return:
     pop         rbx
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index ddcc2c0..c8c8d12 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright (C) 2011, 2016, 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.
@@ -33,7 +34,7 @@
 ; 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
 
 EXTN(jsimd_rgb_gray_convert_avx2):
     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)]
+    ; 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
 
@@ -428,8 +429,8 @@ EXTN(jsimd_rgb_gray_convert_avx2):
     pop         rbx
     vzeroupper
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index f1d399a..7e5a0f2 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; Copyright (C) 2011, 2016, 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.
@@ -32,7 +33,7 @@
 ; 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
 
 EXTN(jsimd_rgb_gray_convert_sse2):
     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)]
+    ; 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
 
@@ -353,8 +354,8 @@ EXTN(jsimd_rgb_gray_convert_sse2):
 .return:
     pop         rbx
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index 9ea6df9..a0eb9ce 100644 (file)
@@ -1,9 +1,10 @@
 ;
 ; 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, 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.
@@ -208,15 +209,15 @@ times 1 << 15 db 16
 ; 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 +232,11 @@ times 1 << 15 db 16
 %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 +244,7 @@ times 1 << 15 db 16
 %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 +260,8 @@ times 1 << 15 db 16
     GLOBAL_FUNCTION(jsimd_huff_encode_one_block_sse2)
 
 EXTN(jsimd_huff_encode_one_block_sse2):
+    push        rbp
+    mov         rbp, rsp
 
 %ifdef WIN64
 
@@ -266,15 +269,15 @@ EXTN(jsimd_huff_encode_one_block_sse2):
 ; 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 +287,10 @@ EXTN(jsimd_huff_encode_one_block_sse2):
     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
 
 %else
 
@@ -301,9 +302,10 @@ EXTN(jsimd_huff_encode_one_block_sse2):
 ; 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
@@ -314,10 +316,13 @@ EXTN(jsimd_huff_encode_one_block_sse2):
     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 +448,9 @@ EXTN(jsimd_huff_encode_one_block_sse2):
     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 +539,8 @@ EXTN(jsimd_huff_encode_one_block_sse2):
     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 +557,17 @@ EXTN(jsimd_huff_encode_one_block_sse2):
                                                           ; 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
 
 ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 01b5c02..11db4b2 100644 (file)
@@ -3,6 +3,7 @@
 ; (64-bit SSE2)
 ;
 ; Copyright (C) 2016, 2018, Matthieu Darbois
+; Copyright (C) 2023, Aliaksiej Kandracienka.
 ;
 ; Based on the x86 SIMD extension for IJG JPEG library
 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
 
 EXTN(jsimd_encode_mcu_AC_first_prepare_sse2):
     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]
+    sub         rsp, SIZEOF_XMMWORD
+    movdqa      XMMWORD [rsp], ZERO
     collect_args 6
 
-    movdqa      XMMWORD [rbp - 16], ZERO
-
     movd        AL, r13d
     pxor        ZERO, ZERO
     mov         K, LEN
@@ -384,10 +381,9 @@ EXTN(jsimd_encode_mcu_AC_first_prepare_sse2):
 
     REDUCE0
 
-    movdqa      ZERO, XMMWORD [rbp - 16]
     uncollect_args 6
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    movdqa      ZERO, XMMWORD [rsp]
+    mov         rsp, rbp
     pop         rbp
     ret
 
@@ -450,16 +446,12 @@ EXTN(jsimd_encode_mcu_AC_first_prepare_sse2):
 
 EXTN(jsimd_encode_mcu_AC_refine_prepare_sse2):
     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]
+    sub         rsp, SIZEOF_XMMWORD
+    movdqa      XMMWORD [rsp], ZERO
     collect_args 6
 
-    movdqa      XMMWORD [rbp - 16], ZERO
-
     xor         SIGN, SIGN
     xor         EOB, EOB
     xor         KK, KK
@@ -606,10 +598,9 @@ EXTN(jsimd_encode_mcu_AC_refine_prepare_sse2):
     REDUCE0
 
     mov         eax, EOB
-    movdqa      ZERO, XMMWORD [rbp - 16]
     uncollect_args 6
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    movdqa      ZERO, XMMWORD [rsp]
+    mov         rsp, rbp
     pop         rbp
     ret
 
index b32527a..589c52b 100644 (file)
@@ -45,7 +45,6 @@
 
 EXTN(jsimd_h2v1_downsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 6
 
@@ -207,7 +206,6 @@ EXTN(jsimd_h2v1_downsample_avx2):
 
 EXTN(jsimd_h2v2_downsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 6
 
index 2fcfe45..7a4f1bc 100644 (file)
@@ -44,7 +44,6 @@
 
 EXTN(jsimd_h2v1_downsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 6
 
@@ -189,7 +188,6 @@ EXTN(jsimd_h2v1_downsample_sse2):
 
 EXTN(jsimd_h2v2_downsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 6
 
index 2370fda..070436c 100644 (file)
@@ -5,6 +5,7 @@
 ; Copyright (C) 2009, 2012, 2016, 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.
@@ -34,7 +35,7 @@
 ; 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
 
 EXTN(jsimd_ycc_rgb_convert_avx2):
     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)]
+    ; 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
 
@@ -486,8 +487,8 @@ EXTN(jsimd_ycc_rgb_convert_avx2):
     pop         rbx
     vzeroupper
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index e07c8d7..bba3a30 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2012, 2016, 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.
@@ -33,7 +34,7 @@
 ; 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
 
 EXTN(jsimd_ycc_rgb_convert_sse2):
     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)]
+    ; 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
 
@@ -429,8 +430,8 @@ EXTN(jsimd_ycc_rgb_convert_sse2):
 .return:
     pop         rbx
     uncollect_args 5
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index 8b264b4..1191645 100644 (file)
@@ -5,6 +5,7 @@
 ; Copyright (C) 2009, 2012, 2016, 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.
@@ -34,7 +35,7 @@
 ; 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
 
 EXTN(jsimd_h2v1_merged_upsample_avx2):
     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)]
+    ; 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
 
@@ -480,8 +481,8 @@ EXTN(jsimd_h2v1_merged_upsample_avx2):
     pop         rbx
     vzeroupper
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
@@ -506,7 +507,6 @@ EXTN(jsimd_h2v1_merged_upsample_avx2):
 
 EXTN(jsimd_h2v2_merged_upsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
     push        rbx
index eb3ab9d..8988dd0 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009, 2012 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2012, 2016, 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.
@@ -33,7 +34,7 @@
 ; 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
 
 EXTN(jsimd_h2v1_merged_upsample_sse2):
     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)]
+    ; 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
 
@@ -422,8 +423,8 @@ EXTN(jsimd_h2v1_merged_upsample_sse2):
 .return:
     pop         rbx
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
@@ -448,7 +449,6 @@ EXTN(jsimd_h2v1_merged_upsample_sse2):
 
 EXTN(jsimd_h2v2_merged_upsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
     push        rbx
index 1e4979f..c6ddbb5 100644 (file)
@@ -5,6 +5,7 @@
 ; Copyright (C) 2009, 2016, 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.
@@ -62,7 +63,6 @@ PW_EIGHT times 16 dw 8
 
 EXTN(jsimd_h2v1_fancy_upsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     push_xmm    3
     collect_args 4
@@ -208,7 +208,7 @@ EXTN(jsimd_h2v1_fancy_upsample_avx2):
 ; 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
@@ -216,12 +216,12 @@ EXTN(jsimd_h2v1_fancy_upsample_avx2):
 
 EXTN(jsimd_h2v2_fancy_upsample_avx2):
     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)]
+    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
@@ -500,8 +500,8 @@ EXTN(jsimd_h2v2_fancy_upsample_avx2):
     vzeroupper
     uncollect_args 4
     pop_xmm     3
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
@@ -525,7 +525,6 @@ EXTN(jsimd_h2v2_fancy_upsample_avx2):
 
 EXTN(jsimd_h2v1_upsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
 
@@ -614,7 +613,6 @@ EXTN(jsimd_h2v1_upsample_avx2):
 
 EXTN(jsimd_h2v2_upsample_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
     push        rbx
index 38dbcee..24cd389 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 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.
@@ -61,7 +62,6 @@ PW_EIGHT times 8 dw 8
 
 EXTN(jsimd_h2v1_fancy_upsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
 
@@ -195,7 +195,7 @@ EXTN(jsimd_h2v1_fancy_upsample_sse2):
 ; 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
@@ -203,12 +203,12 @@ EXTN(jsimd_h2v1_fancy_upsample_sse2):
 
 EXTN(jsimd_h2v2_fancy_upsample_sse2):
     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)]
+    ; 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
 
@@ -473,8 +473,8 @@ EXTN(jsimd_h2v2_fancy_upsample_sse2):
 .return:
     pop         rbx
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
@@ -498,7 +498,6 @@ EXTN(jsimd_h2v2_fancy_upsample_sse2):
 
 EXTN(jsimd_h2v1_upsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
 
@@ -585,7 +584,6 @@ EXTN(jsimd_h2v1_upsample_sse2):
 
 EXTN(jsimd_h2v2_upsample_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
     push        rbx
index ef27966..3595496 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
 ;
 ; Based on the x86 SIMD extension for IJG JPEG library
 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -58,7 +59,7 @@ PD_1_306 times 4 dd 1.306562964876376527856643
 
 ; 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
@@ -66,12 +67,12 @@ PD_1_306 times 4 dd 1.306562964876376527856643
 
 EXTN(jsimd_fdct_float_sse):
     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)]
+    ; 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.
@@ -345,8 +346,8 @@ EXTN(jsimd_fdct_float_sse):
     jnz         near .columnloop
 
     uncollect_args 1
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index 2e1bfe6..d33c58a 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
 ;
 ; Based on the x86 SIMD extension for IJG JPEG library
 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -73,7 +74,7 @@ PW_F1306 times 8 dw F_1_306 << CONST_SHIFT
 
 ; 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
@@ -81,12 +82,12 @@ PW_F1306 times 8 dw F_1_306 << CONST_SHIFT
 
 EXTN(jsimd_fdct_ifast_sse2):
     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)]
+    ; 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.
@@ -379,8 +380,8 @@ EXTN(jsimd_fdct_ifast_sse2):
     movdqa      XMMWORD [XMMBLOCK(1,0,rdx,SIZEOF_DCTELEM)], xmm2
 
     uncollect_args 1
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index e56258b..d0afe5e 100644 (file)
@@ -261,7 +261,6 @@ PW_1_NEG1                  times 8  dw  1
 
 EXTN(jsimd_fdct_islow_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 1
 
index ec1f383..024ce90 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 2020, D. R. Commander.
+; Copyright (C) 2023, Aliaksiej Kandracienka.
 ;
 ; Based on the x86 SIMD extension for IJG JPEG library
 ; Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -94,7 +95,7 @@ PW_DESCALE_P2X times 8 dw  1 << (PASS1_BITS - 1)
 
 ; 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
@@ -102,12 +103,12 @@ PW_DESCALE_P2X times 8 dw  1 << (PASS1_BITS - 1)
 
 EXTN(jsimd_fdct_islow_sse2):
     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)]
+    ; 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.
@@ -609,8 +610,8 @@ EXTN(jsimd_fdct_islow_sse2):
     movdqa      XMMWORD [XMMBLOCK(3,0,rdx,SIZEOF_DCTELEM)], xmm3
 
     uncollect_args 1
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index 60bf961..952fbe3 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 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.
@@ -65,8 +66,7 @@ PB_CENTERJSAMP  times 16 db  CENTERJSAMPLE
 ; 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
@@ -77,11 +77,11 @@ PB_CENTERJSAMP  times 16 db  CENTERJSAMPLE
 
 EXTN(jsimd_idct_float_sse2):
     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
     push        rbx
@@ -322,7 +322,6 @@ EXTN(jsimd_idct_float_sse2):
 
     ; ---- 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
@@ -472,8 +471,8 @@ EXTN(jsimd_idct_float_sse2):
 
     pop         rbx
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index cb97fdf..a3da8d8 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 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.
@@ -86,8 +87,7 @@ PB_CENTERJSAMP times 16 db  CENTERJSAMPLE
 ; 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
 
@@ -96,12 +96,12 @@ PB_CENTERJSAMP times 16 db  CENTERJSAMPLE
 
 EXTN(jsimd_idct_ifast_sse2):
     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)]
+    ; 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 +320,6 @@ EXTN(jsimd_idct_ifast_sse2):
 
     ; ---- Pass 2: process rows from work array, store into output array.
 
-    mov         rax, [original_rbp]
     mov         rdi, r12                ; (JSAMPROW *)
     mov         eax, r13d
 
@@ -480,8 +479,8 @@ EXTN(jsimd_idct_ifast_sse2):
     movq        XMM_MMWORD [rsi+rax*SIZEOF_JSAMPLE], xmm2
 
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
     ret
index ca7e317..528da01 100644 (file)
@@ -283,7 +283,6 @@ PW_1_NEG1                  times 8  dw  1
 
 EXTN(jsimd_idct_islow_avx2):
     push        rbp
-    mov         rax, rsp                     ; rax = original rbp
     mov         rbp, rsp                     ; rbp = aligned rbp
     push_xmm    4
     collect_args 4
index 7aa869b..92f633e 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 2020, 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.
@@ -99,8 +100,7 @@ PB_CENTERJSAMP times 16 db  CENTERJSAMPLE
 ; 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
 
@@ -109,12 +109,12 @@ PB_CENTERJSAMP times 16 db  CENTERJSAMPLE
 
 EXTN(jsimd_idct_islow_sse2):
     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)]
+    ; 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 +512,6 @@ EXTN(jsimd_idct_islow_sse2):
 
     ; ---- Pass 2: process rows from work array, store into output array.
 
-    mov         rax, [original_rbp]
     mov         rdi, r12                ; (JSAMPROW *)
     mov         eax, r13d
 
@@ -837,8 +836,8 @@ EXTN(jsimd_idct_islow_sse2):
     movq        XMM_MMWORD [rsi+rax*SIZEOF_JSAMPLE], xmm5
 
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
index 4ece9d8..1ec500c 100644 (file)
@@ -4,6 +4,7 @@
 ; Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
 ; Copyright (C) 2009, 2016, 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.
@@ -107,8 +108,7 @@ PB_CENTERJSAMP  times 16 db  CENTERJSAMPLE
 ; 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
 
@@ -117,12 +117,12 @@ PB_CENTERJSAMP  times 16 db  CENTERJSAMPLE
 
 EXTN(jsimd_idct_4x4_sse2):
     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)]
+    ; 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 +309,6 @@ EXTN(jsimd_idct_4x4_sse2):
 
     ; ---- Pass 2: process rows, store into output array.
 
-    mov         rax, [original_rbp]
     mov         rdi, r12                ; (JSAMPROW *)
     mov         eax, r13d
 
@@ -390,8 +389,8 @@ EXTN(jsimd_idct_4x4_sse2):
     movd        XMM_DWORD [rsi+rax*SIZEOF_JSAMPLE], xmm3
 
     uncollect_args 4
-    mov         rsp, rbp                ; rsp <- aligned rbp
-    pop         rsp                     ; rsp <- original rbp
+    lea         rsp, [rbp-8]
+    pop         r15
     pop         rbp
     ret
 
@@ -415,7 +414,6 @@ EXTN(jsimd_idct_4x4_sse2):
 
 EXTN(jsimd_idct_2x2_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 4
     push        rbx
index ab2e395..232bbb2 100644 (file)
@@ -38,7 +38,6 @@
 
 EXTN(jsimd_convsamp_float_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
     push        rbx
@@ -111,7 +110,6 @@ EXTN(jsimd_convsamp_float_sse2):
 
 EXTN(jsimd_quantize_float_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
 
index 70fe811..66104d7 100644 (file)
@@ -39,7 +39,6 @@
 
 EXTN(jsimd_convsamp_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
 
@@ -117,7 +116,6 @@ EXTN(jsimd_convsamp_avx2):
 
 EXTN(jsimd_quantize_avx2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
 
index 3ee4420..11e9f4c 100644 (file)
@@ -38,7 +38,6 @@
 
 EXTN(jsimd_convsamp_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
     push        rbx
@@ -117,7 +116,6 @@ EXTN(jsimd_convsamp_sse2):
 
 EXTN(jsimd_quantize_sse2):
     push        rbp
-    mov         rax, rsp
     mov         rbp, rsp
     collect_args 3
 
index 584a010..3f5ee77 100644 (file)
@@ -2,8 +2,8 @@
  * jsimd_x86_64.c
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
  *
  * Based on the x86 SIMD extension for IJG JPEG library,
  * Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -21,7 +21,6 @@
 #include "../../jdct.h"
 #include "../../jsimddct.h"
 #include "../jsimd.h"
-#include "jconfigint.h"
 
 /*
  * In the PIC cases, we have no guarantee that constants will keep
 #define IS_ALIGNED_SSE(ptr)  (IS_ALIGNED(ptr, 4)) /* 16 byte alignment */
 #define IS_ALIGNED_AVX(ptr)  (IS_ALIGNED(ptr, 5)) /* 32 byte alignment */
 
-static unsigned int simd_support = (unsigned int)(~0);
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = (unsigned int)(~0);
+static THREAD_LOCAL unsigned int simd_huffman = 1;
 
 /*
  * Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
  */
 LOCAL(void)
 init_simd(void)
@@ -148,6 +145,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
   void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
   void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->in_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -197,6 +197,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
   void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
   void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->in_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -246,6 +249,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -336,6 +342,9 @@ GLOBAL(void)
 jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
                       JSAMPARRAY input_data, JSAMPARRAY output_data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
                                compptr->v_samp_factor,
@@ -352,6 +361,9 @@ GLOBAL(void)
 jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
                       JSAMPARRAY input_data, JSAMPARRAY output_data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
                                compptr->v_samp_factor,
@@ -406,6 +418,9 @@ GLOBAL(void)
 jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                     JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
                              input_data, output_data_ptr);
@@ -418,6 +433,9 @@ GLOBAL(void)
 jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                     JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
                              input_data, output_data_ptr);
@@ -472,6 +490,9 @@ GLOBAL(void)
 jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                           JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
                                    compptr->downsampled_width, input_data,
@@ -486,6 +507,9 @@ GLOBAL(void)
 jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                           JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
                                    compptr->downsampled_width, input_data,
@@ -545,6 +569,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -593,6 +620,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
   void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
   void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
 
+  if (simd_support == ~0U)
+    init_simd();
+
   switch (cinfo->out_color_space) {
   case JCS_EXT_RGB:
     avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -682,6 +712,9 @@ GLOBAL(void)
 jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
                DCTELEM *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_convsamp_avx2(sample_data, start_col, workspace);
   else
@@ -751,6 +784,9 @@ jsimd_can_fdct_float(void)
 GLOBAL(void)
 jsimd_fdct_islow(DCTELEM *data)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_fdct_islow_avx2(data);
   else
@@ -812,6 +848,9 @@ jsimd_can_quantize_float(void)
 GLOBAL(void)
 jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_quantize_avx2(coef_block, divisors, workspace);
   else
@@ -966,6 +1005,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
                  JDIMENSION output_col)
 {
+  if (simd_support == ~0U)
+    init_simd();
+
   if (simd_support & JSIMD_AVX2)
     jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
                           output_col);
@@ -1036,7 +1078,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
 GLOBAL(void)
 jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
                                   const int *jpeg_natural_order_start, int Sl,
-                                  int Al, JCOEF *values, size_t *zerobits)
+                                  int Al, UJCOEF *values, size_t *zerobits)
 {
   jsimd_encode_mcu_AC_first_prepare_sse2(block, jpeg_natural_order_start,
                                          Sl, Al, values, zerobits);
@@ -1060,7 +1102,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
 GLOBAL(int)
 jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
                                    const int *jpeg_natural_order_start, int Sl,
-                                   int Al, JCOEF *absvalues, size_t *bits)
+                                   int Al, UJCOEF *absvalues, size_t *bits)
 {
   return jsimd_encode_mcu_AC_refine_prepare_sse2(block,
                                                  jpeg_natural_order_start,
index 705f813..251bc4c 100644 (file)
@@ -3,6 +3,7 @@
 ;
 ; 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
@@ -31,6 +32,8 @@
     GLOBAL_FUNCTION(jpeg_simd_cpu_support)
 
 EXTN(jpeg_simd_cpu_support):
+    push        rbp
+    mov         rbp, rsp
     push        rbx
     push        rdi
 
@@ -79,6 +82,7 @@ EXTN(jpeg_simd_cpu_support):
 
     pop         rdi
     pop         rbx
+    pop         rbp
     ret
 
 ; For some reason, the OS X linker does not honor the request to align the
index 88b568c..3d5e004 100644 (file)
--- a/strtest.c
+++ b/strtest.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2022 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2022-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -55,8 +55,12 @@ void invalid_parameter_handler(const wchar_t *expression,
 
 int main(int argc, char **argv)
 {
+#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);
index 15b8d37..030b8e8 100644 (file)
@@ -2,8 +2,10 @@ 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.
+Lossless JPEG Modifications:
+Copyright (C) 1999, Ken Murchison.
+libjpeg-turbo Modifications:
+Copyright (C) 2022-2023, D. R. Commander.
 For conditions of distribution and use, see the accompanying README.ijg file.
 
 
@@ -23,8 +25,10 @@ In this document, JPEG-specific terminology follows the JPEG standard:
   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
+  A "data unit" is an abstract data type that is either a block for lossy
+        (DCT-based) codecs or a sample for lossless (predictive) codecs.
+  An "MCU" (minimum coded unit) is an interleaved set of data units of size
+        determined by the sampling factors, or a single data unit 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
@@ -45,22 +49,14 @@ 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.
+sequential, progressive DCT, and lossless (spatial) processes.  Hierarchical
+processes are not supported.
 
 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.
+never be; nonintegral sampling ratios are the prime example.
 
 By itself, the library handles only interchange JPEG datastreams --- in
 particular the widely used JFIF file format.  The library can be used by
@@ -103,9 +99,13 @@ elements:
     * 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:
+  Lossy JPEG proper:
     * MCU assembly, DCT, quantization.
     * Entropy coding (sequential or progressive, Huffman or arithmetic).
+  Lossless JPEG proper:
+    * Point transform.
+    * Prediction, differencing.
+    * Entropy coding (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
@@ -115,9 +115,13 @@ do something else with the data.
 
 The decompressor library contains the following main elements:
 
-  JPEG proper:
+  Lossy JPEG proper:
     * Entropy decoding (sequential or progressive, Huffman or arithmetic).
     * Dequantization, inverse DCT, MCU disassembly.
+  Lossless JPEG proper:
+    * Entropy decoding (Huffman or arithmetic).
+    * Prediction, undifferencing.
+    * Point transform, sample size scaling.
   Postprocessing:
     * Upsampling.  Optionally, this step may be able to do more general
       rescaling of the image.
@@ -283,7 +287,8 @@ task performed by any one controller.
 
 *** Compression object structure ***
 
-Here is a sketch of the logical structure of the JPEG compression library:
+Here is a sketch of the logical structure of the JPEG compression library in
+lossy mode:
 
                                                  |-- Colorspace conversion
                   |-- Preprocessing controller --|
@@ -293,6 +298,19 @@ Main controller --|
                   |-- Coefficient controller --|
                                                |-- Entropy encoding
 
+... and in lossless mode:
+
+                                                 |-- Colorspace conversion
+                  |-- Preprocessing controller --|
+                  |                              |-- Downsampling
+Main controller --|
+                  |                           |-- Point transform
+                  |                           |
+                  |-- Difference controller --|-- Prediction, differencing
+                                              |
+                                              |-- Lossless mode 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
@@ -346,6 +364,22 @@ The objects shown above are:
   during each pass, and the coder must emit the appropriate subset of
   coefficients.
 
+* Difference controller: buffer controller for the spatial difference data.
+  When 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.
+
+* Point transform: Downscale the data by the point transform value.
+
+* Prediction and differencing: Calculate the predictor and subtract it
+  from the input.  Works on one scanline per call.  The difference
+  controller supplies the prior scanline, which is used for prediction.
+
+* Lossless mode entropy encoding: Perform Huffman or arithmetic entropy coding
+  and emit the coded data to the data destination module.  This module handles
+  MCU assembly.  Works on one MCU row per call.
+
 In addition to the above objects, the compression library includes these
 objects:
 
@@ -386,7 +420,8 @@ 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:
+Here is a sketch of the logical structure of the JPEG decompression library in
+lossy mode:
 
                                                |-- Entropy decoding
                   |-- Coefficient controller --|
@@ -397,6 +432,20 @@ Main controller --|
                                                   |-- Color quantization
                                                   |-- Color precision reduction
 
+... and in lossless mode:
+
+                                              |-- Lossless mode entropy
+                                              |   decoding
+                                              |
+                  |-- Difference controller --|-- Prediction, undifferencing
+                  |                           |
+                  |                           |-- Point transform, sample size
+                  |                               scaling
+Main controller --|
+                  |                               |-- Upsampling
+                  |-- Postprocessing controller --|
+                                                  |-- Color precision reduction
+
 As before, this diagram also represents typical control flow.  The objects
 shown are:
 
@@ -430,6 +479,22 @@ shown are:
   that emit fewer samples per DCT block, not the full 8x8.  Works on one DCT
   block at a time.
 
+* Difference controller: buffer controller for the spatial difference data.
+  When reading a multiscan JPEG file, this controller is responsible for
+  buffering the full image. The equivalent of one fully interleaved MCU row
+  is processed per call, even when the source JPEG file is noninterleaved.
+
+* Lossless mode entropy decoding: Read coded data from the data source module
+  and perform Huffman or arithmetic entropy decoding.  Works on one MCU row per
+  call.
+
+* Prediction and undifferencing: Calculate the predictor and add it to the
+  decoded difference.  Works on one scanline per call.  The difference
+  controller supplies the prior scanline, which is used for prediction.
+
+* Point transform and sample size scaling: Upscale the data by the point
+  transform value and downscale it to fit into the compiled-in sample size.
+
 * 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
@@ -453,9 +518,9 @@ shown are:
   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.
+  design, the output values are JSAMPLEs, J12SAMPLEs, or J16SAMPLEs, so the
+  library cannot quantize to more than 256 colors when using 8-bit data
+  precision.  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.
@@ -541,28 +606,44 @@ there isn't any real need for it.
 
 *** Data formats ***
 
-Arrays of pixel sample values use the following data structure:
+Arrays of 8-bit 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.
+Arrays of 12-bit pixel sample values use the following data structure:
+
+    typedef something J12SAMPLE;        a pixel component value, 0..MAXJ12SAMPLE
+    typedef J12SAMPLE *J12SAMPROW;      ptr to a row of samples
+    typedef J12SAMPROW *J12SAMPARRAY;   ptr to a list of rows
+    typedef J12SAMPARRAY *J12SAMPIMAGE; ptr to a list of color-component arrays
+
+Arrays of 16-bit pixel sample values use the following data structure:
 
-With these conventions, JSAMPLE values can be assumed to be >= 0.  This helps
+    typedef something J16SAMPLE;        a pixel component value, 0..MAXJ16SAMPLE
+    typedef J16SAMPLE *J16SAMPROW;      ptr to a row of samples
+    typedef J16SAMPROW *J16SAMPARRAY;   ptr to a list of rows
+    typedef J16SAMPARRAY *J16SAMPIMAGE; ptr to a list of color-component arrays
+
+The basic element type JSAMPLE (8-bit sample) will be unsigned char, the basic
+element type J12SAMPLE (12-bit sample) will be short, and the basic element
+type J16SAMPLE (16-bit sample) will be unsigned short.
+
+With these conventions, J*SAMPLE 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
+specification that 8-bit 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
+0..255.  (NOTE: different values are required when 12-bit samples are in use.
+When 8-bit samples are in use, the code uses MAXJSAMPLE and CENTERJSAMPLE,
+which are defined as 255 and 128 respectively.  When 12-bit samples are in use,
+the code uses MAXJ12SAMPLE and CENTERJ12SAMPLE, which are defined as 4095 and
+2048 respectively.  When 16-bit samples are in use, the code uses MAXJ16SAMPLE
+and CENTERJ16SAMPLE, which are defined as 65535 and 32768 respectively.)
+
+We use a pointer per row, rather than a two-dimensional J*SAMPLE 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
@@ -592,9 +673,9 @@ 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
+represented by N consecutive J*SAMPLE values, and an image row is an array of
+(# of color components)*(image width) J*SAMPLEs.  One or more rows of data can
+be represented by a pointer of type J*SAMPARRAY 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.)
@@ -733,17 +814,17 @@ The memory manager deals with three kinds of object:
    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
+3. "Virtual" objects.  These are large 2-D arrays of J*SAMPLEs 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
+(Note: J*SAMPARRAY 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.)
+and a J*SAMPARRAY 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
@@ -770,7 +851,7 @@ 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
+  2. All "large" objects (including J*SAMPARRAYs 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
diff --git a/testimages/big_building16.ppm b/testimages/big_building16.ppm
new file mode 100644 (file)
index 0000000..b0b8439
Binary files /dev/null and b/testimages/big_building16.ppm differ
diff --git a/testimages/big_tree8.bmp b/testimages/big_tree8.bmp
new file mode 100644 (file)
index 0000000..b1dfc45
Binary files /dev/null and b/testimages/big_tree8.bmp differ
similarity index 93%
rename from testimages/nightshot_iso_100.txt
rename to testimages/big_tree8.txt
index 9320886..2f0be72 100644 (file)
@@ -1,5 +1,5 @@
-libjpeg-turbo note:  This image was extracted from the 8-bit nightshot_iso_100
-image.  The original can be downloaded at the link below.
+libjpeg-turbo note:  This image was extracted from the 8-bit big_tree image.
+The original can be downloaded at the link below.
 
 The New Image Compression Test Set - Jan 2008
 http://www.imagecompression.info/test_images
diff --git a/testimages/nightshot_iso_100.bmp b/testimages/nightshot_iso_100.bmp
deleted file mode 100644 (file)
index 5a27151..0000000
Binary files a/testimages/nightshot_iso_100.bmp and /dev/null differ
index 0089302..c7d97d0 100644 (file)
--- a/tjbench.c
+++ b/tjbench.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2009-2019, 2021-2022 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2009-2019, 2021-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
 #define THROW_UNIX(m)  THROW(m, strerror(errno))
 #endif
 
-char tjErrorStr[JMSG_LENGTH_MAX] = "\0", tjErrorMsg[JMSG_LENGTH_MAX] = "\0";
+char tjErrorStr[JMSG_LENGTH_MAX] = "\0";
 int tjErrorLine = -1, tjErrorCode = -1;
 
-#define THROW_TJG(m) { \
-  printf("ERROR in line %d while %s:\n%s\n", __LINE__, m, \
-         tjGetErrorStr2(NULL)); \
+#define THROW_TJG() { \
+  printf("ERROR in line %d\n%s\n", __LINE__, tj3GetErrorStr(NULL)); \
   retval = -1;  goto bailout; \
 }
 
-#define THROW_TJ(m) { \
-  int _tjErrorCode = tjGetErrorCode(handle); \
-  char *_tjErrorStr = tjGetErrorStr2(handle); \
+#define THROW_TJ() { \
+  int _tjErrorCode = tj3GetErrorCode(handle); \
+  char *_tjErrorStr = tj3GetErrorStr(handle); \
   \
-  if (!(flags & TJFLAG_STOPONWARNING) && _tjErrorCode == TJERR_WARNING) { \
+  if (!tj3Get(handle, TJPARAM_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__; \
-      printf("WARNING in line %d while %s:\n%s\n", __LINE__, m, _tjErrorStr); \
+      printf("WARNING in line %d:\n%s\n", __LINE__, _tjErrorStr); \
     } \
   } else { \
-    printf("%s in line %d while %s:\n%s\n", \
-           _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, m, \
+    printf("%s in line %d:\n%s\n", \
+           _tjErrorCode == TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, \
            _tjErrorStr); \
     retval = -1;  goto bailout; \
   } \
 }
 
-int flags = TJFLAG_NOREALLOC, compOnly = 0, decompOnly = 0, doYUV = 0,
-  quiet = 0, doTile = 0, pf = TJPF_BGR, yuvPad = 1, doWrite = 1;
+#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))
+
+int stopOnWarning = 0, bottomUp = 0, noRealloc = 1, fastUpsample = 0,
+  fastDCT = 0, optimize = 0, progressive = 0, limitScans = 0, arithmetic = 0,
+  lossless = 0, restartIntervalBlocks = 0, restartIntervalRows = 0;
+int precision = 8, sampleSize, compOnly = 0, decompOnly = 0, doYUV = 0,
+  quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
 char *ext = "ppm";
 const char *pixFormatStr[TJ_NUMPF] = {
   "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
 };
 const char *subNameLong[TJ_NUMSAMP] = {
-  "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
+  "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
 };
 const char *csName[TJ_NUMCS] = {
   "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
 };
 const char *subName[TJ_NUMSAMP] = {
-  "444", "422", "420", "GRAY", "440", "411"
+  "444", "422", "420", "GRAY", "440", "411", "441"
 };
 tjscalingfactor *scalingFactors = NULL, sf = { 1, 1 };
+tjregion cr = { 0, 0, 0, 0 };
 int nsf = 0, xformOp = TJXOP_NONE, xformOpt = 0;
 int (*customFilter) (short *, tjregion, tjregion, int, int, tjtransform *);
 double benchTime = 5.0, warmup = 1.0;
@@ -113,13 +124,25 @@ 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]);
+  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
-    return (char *)csName[cs];
+  } 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;
+    }
+  }
 }
 
 
@@ -151,50 +174,85 @@ static int dummyDCTFilter(short *coeffs, tjregion arrayRegion,
 
 
 /* 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)
+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[13] = "\0", *ptr;
+  char tempStr[1024], sizeStr[24] = "\0", qualStr[16] = "\0";
   FILE *file = NULL;
   tjhandle handle = NULL;
-  int row, col, iter = 0, dstBufAlloc = 0, retval = 0;
+  int i, 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 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, 13, "_Q%d", jpegQual);
-    qualStr[12] = 0;
+    SNPRINTF(qualStr, 16, "_%s%d", lossless ? "PSV" : "Q", jpegQual);
+    qualStr[15] = 0;
   }
 
-  if ((handle = tjInitDecompress()) == NULL)
-    THROW_TJ("executing tjInitDecompress()");
+  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, limitScans ? 500 : 0) == -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 ((unsigned long long)pitch * (unsigned long long)scaledh >
-        (unsigned long long)((size_t)-1))
+    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");
-    if ((dstBuf = (unsigned char *)malloc((size_t)pitch * scaledh)) == NULL)
+    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 */
-  memset(dstBuf, 127, (size_t)pitch * scaledh);
+  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;
-    unsigned long yuvSize = tjBufSizeYUV2(width, yuvPad, height, subsamp);
+    size_t yuvSize = tj3YUVBufSize(width, yuvAlign, height, subsamp);
 
-    if (yuvSize == (unsigned long)-1)
-      THROW_TJ("allocating YUV buffer");
+    if (yuvSize == 0)
+      THROW_TJG();
     if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
       THROW_UNIX("allocating YUV buffer");
     memset(yuvBuf, 127, yuvSize);
@@ -208,27 +266,38 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
     double start = getTime();
 
     for (row = 0, dstPtr = dstBuf; row < ntilesh;
-         row++, dstPtr += (size_t)pitch * tileh) {
+         row++, dstPtr += (size_t)pitch * tileh * sampleSize) {
       for (col = 0, dstPtr2 = dstPtr; col < ntilesw;
-           col++, tile++, dstPtr2 += ps * tilew) {
+           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 (tjDecompressToYUV2(handle, jpegBuf[tile], jpegSize[tile], yuvBuf,
-                                 width, yuvPad, height, flags) == -1)
-            THROW_TJ("executing tjDecompressToYUV2()");
+          if (tj3DecompressToYUV8(handle, jpegBufs[tile], jpegSizes[tile],
+                                  yuvBuf, yuvAlign) == -1)
+            THROW_TJ();
           startDecode = getTime();
-          if (tjDecodeYUV(handle, yuvBuf, yuvPad, subsamp, dstPtr2, width,
-                          pitch, height, pf, flags) == -1)
-            THROW_TJ("executing tjDecodeYUV()");
+          if (tj3DecodeYUV8(handle, yuvBuf, yuvAlign, dstPtr2, width, pitch,
+                            height, pf) == -1)
+            THROW_TJ();
           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()");
+        } 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;
@@ -242,9 +311,6 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
   }
   if (doYUV) elapsed -= elapsedDecode;
 
-  if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
-  handle = NULL;
-
   if (quiet) {
     printf("%-6s%s",
            sigfig((double)(w * h) / 1000000. * (double)iter / elapsed, 4,
@@ -278,80 +344,58 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
   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 bitmap");
-  ptr = strrchr(tempStr, '.');
-  SNPRINTF(ptr, 1024 - (ptr - tempStr), "-err.%s", ext);
-  if (srcBuf && sf.num == 1 && sf.denom == 1) {
-    if (!quiet) printf("Compression error written to %s.\n", tempStr);
-    if (subsamp == TJ_GRAYSCALE) {
-      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 bitmap");
+    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);
-  if (handle) tjDestroy(handle);
+  tj3Destroy(handle);
   if (dstBufAlloc) free(dstBuf);
   free(yuvBuf);
   return retval;
 }
 
 
-static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
+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;
-  tjhandle handle = NULL;
-  unsigned char **jpegBuf = NULL, *yuvBuf = NULL, *tmpBuf = NULL, *srcPtr,
-    *srcPtr2;
+  unsigned char **jpegBufs = NULL, *yuvBuf = NULL, *srcPtr, *srcPtr2;
+  void *tmpBuf = NULL;
   double start, elapsed, elapsedEncode;
-  int totalJpegSize = 0, row, col, i, tilew = w, tileh = h, retval = 0;
+  int row, col, i, tilew = w, tileh = h, retval = 0;
   int iter;
-  unsigned long *jpegSize = NULL, yuvSize = 0;
+  size_t totalJpegSize = 0, *jpegSizes = 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))
+  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");
-  if ((tmpBuf = (unsigned char *)malloc((size_t)pitch * h)) == NULL)
+  if ((tmpBuf = malloc((size_t)pitch * h * sampleSize)) == NULL)
     THROW_UNIX("allocating temporary image buffer");
 
   if (!quiet)
-    printf(">>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n", pfStr,
-           (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down",
-           subNameLong[subsamp], jpegQual);
+    printf(">>>>>  %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) {
@@ -360,38 +404,70 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
     ntilesw = (w + tilew - 1) / tilew;
     ntilesh = (h + tileh - 1) / tileh;
 
-    if ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
-                                            ntilesw * ntilesh)) == NULL)
+    if ((jpegBufs = (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)
+    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(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
+    memset(jpegSizes, 0, sizeof(size_t) * ntilesw * ntilesh);
 
-    if ((flags & TJFLAG_NOREALLOC) != 0)
+    if (noRealloc) {
       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)
+        size_t jpegBufSize = tj3JPEGBufSize(tilew, tileh, subsamp);
+
+        if (jpegBufSize == 0)
+          THROW_TJG();
+        if ((jpegBufs[i] = tj3Alloc(jpegBufSize)) == NULL)
           THROW_UNIX("allocating JPEG tiles");
       }
+    }
 
     /* Compression test */
     if (quiet == 1)
-      printf("%-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()");
+      printf("%-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 (doYUV) {
-      yuvSize = tjBufSizeYUV2(tilew, yuvPad, tileh, subsamp);
-      if (yuvSize == (unsigned long)-1)
-        THROW_TJ("allocating YUV buffer");
+      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);
@@ -406,30 +482,39 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
       totalJpegSize = 0;
       start = getTime();
       for (row = 0, srcPtr = srcBuf; row < ntilesh;
-           row++, srcPtr += pitch * tileh) {
+           row++, srcPtr += pitch * tileh * sampleSize) {
         for (col = 0, srcPtr2 = srcPtr; col < ntilesw;
-             col++, tile++, srcPtr2 += ps * tilew) {
+             col++, tile++, srcPtr2 += ps * tilew * sampleSize) {
           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,
-                             yuvPad, subsamp, flags) == -1)
-              THROW_TJ("executing tjEncodeYUV3()");
+            if (tj3EncodeYUV8(handle, srcPtr2, width, pitch, height, pf,
+                              yuvBuf, yuvAlign) == -1)
+              THROW_TJ();
             if (iter >= 0) elapsedEncode += getTime() - startEncode;
-            if (tjCompressFromYUV(handle, yuvBuf, width, yuvPad, height,
-                                  subsamp, &jpegBuf[tile], &jpegSize[tile],
-                                  jpegQual, flags) == -1)
-              THROW_TJ("executing tjCompressFromYUV()");
+            if (tj3CompressFromYUV8(handle, yuvBuf, width, yuvAlign, height,
+                                    &jpegBufs[tile], &jpegSizes[tile]) == -1)
+              THROW_TJ();
           } else {
-            if (tjCompress2(handle, srcPtr2, width, pitch, height, pf,
-                            &jpegBuf[tile], &jpegSize[tile], subsamp, jpegQual,
-                            flags) == -1)
-              THROW_TJ("executing tjCompress2()");
+            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 += jpegSize[tile];
+          totalJpegSize += jpegSizes[tile];
         }
       }
       elapsed += getTime() - start;
@@ -443,9 +528,6 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
     }
     if (doYUV) elapsed -= elapsedEncode;
 
-    if (tjDestroy(handle) == -1) THROW_TJ("executing tjDestroy()");
-    handle = NULL;
-
     if (quiet == 1) printf("%-5d  %-5d   ", tilew, tileh);
     if (quiet) {
       if (doYUV)
@@ -466,7 +548,8 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
       if (doYUV) {
         printf("Encode YUV    --> Frame rate:         %f fps\n",
                (double)iter / elapsedEncode);
-        printf("                  Output image size:  %lu bytes\n", yuvSize);
+        printf("                  Output image size:  %lu bytes\n",
+               (unsigned long)yuvSize);
         printf("                  Compression ratio:  %f:1\n",
                (double)(w * h * ps) / (double)yuvSize);
         printf("                  Throughput:         %f Megapixels/sec\n",
@@ -477,8 +560,8 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
       printf("%s --> Frame rate:         %f fps\n",
              doYUV ? "Comp from YUV" : "Compress     ",
              (double)iter / elapsed);
-      printf("                  Output image size:  %d bytes\n",
-             totalJpegSize);
+      printf("                  Output image size:  %lu bytes\n",
+             (unsigned long)totalJpegSize);
       printf("                  Compression ratio:  %f:1\n",
              (double)(w * h * ps) / (double)totalJpegSize);
       printf("                  Throughput:         %f Megapixels/sec\n",
@@ -487,11 +570,12 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
              (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);
+     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(jpegBuf[0], jpegSize[0], 1, file) != 1)
+      if (fwrite(jpegBufs[0], jpegSizes[0], 1, file) != 1)
         THROW_UNIX("writing reference image");
       fclose(file);  file = NULL;
       if (!quiet) printf("Reference image written to %s\n", tempStr);
@@ -499,17 +583,17 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
 
     /* Decompression test */
     if (!compOnly) {
-      if (decomp(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
+      if (decomp(jpegBufs, jpegSizes, tmpBuf, w, h, subsamp, jpegQual,
                  fileName, tilew, tileh) == -1)
         goto bailout;
     } else if (quiet == 1) printf("N/A\n");
 
     for (i = 0; i < ntilesw * ntilesh; i++) {
-      tjFree(jpegBuf[i]);
-      jpegBuf[i] = NULL;
+      tj3Free(jpegBufs[i]);
+      jpegBufs[i] = NULL;
     }
-    free(jpegBuf);  jpegBuf = NULL;
-    free(jpegSize);  jpegSize = NULL;
+    free(jpegBufs);  jpegBufs = NULL;
+    free(jpegSizes);  jpegSizes = NULL;
     if (doYUV) {
       free(yuvBuf);  yuvBuf = NULL;
     }
@@ -519,15 +603,14 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
 
 bailout:
   if (file) fclose(file);
-  if (jpegBuf) {
+  if (jpegBufs) {
     for (i = 0; i < ntilesw * ntilesh; i++)
-      tjFree(jpegBuf[i]);
+      tj3Free(jpegBufs[i]);
   }
-  free(jpegBuf);
+  free(jpegBufs);
   free(yuvBuf);
-  free(jpegSize);
+  free(jpegSizes);
   free(tmpBuf);
-  if (handle) tjDestroy(handle);
   return retval;
 }
 
@@ -536,22 +619,22 @@ static int decompTest(char *fileName)
 {
   FILE *file = NULL;
   tjhandle handle = NULL;
-  unsigned char **jpegBuf = NULL, *srcBuf = NULL;
-  unsigned long *jpegSize = NULL, srcSize, totalJpegSize;
+  unsigned char **jpegBufs = NULL, *srcBuf = NULL;
+  size_t *jpegSizes = 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;
+  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 ((file = fopen(fileName, "rb")) == NULL)
     THROW_UNIX("opening file");
   if (fseek(file, 0, SEEK_END) < 0 ||
-      (srcSize = ftell(file)) == (unsigned long)-1)
+      (srcSize = ftell(file)) == (size_t)-1)
     THROW_UNIX("determining file size");
   if ((srcBuf = (unsigned char *)malloc(srcSize)) == NULL)
     THROW_UNIX("allocating memory");
@@ -564,68 +647,114 @@ static int decompTest(char *fileName)
   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 ((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, limitScans ? 500 : 0) == -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)
+    printf("JPEG image uses progressive entropy coding\n\n");
+  if (tj3Get(handle, TJPARAM_ARITHMETIC) == 1)
+    printf("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) {
     printf("All performance values in Mpixels/sec\n\n");
-    printf("Bitmap     JPEG   JPEG     %s  %s   Xform   Comp    Decomp  ",
+    printf("Pixel     JPEG             %s  %s   Xform   Comp    Decomp  ",
            doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
     if (doYUV) printf("Decode");
     printf("\n");
-    printf("Format     CS     Subsamp  Width  Height  Perf    Ratio   Perf    ");
+    printf("Format    Format           Width  Height  Perf    Ratio   Perf    ");
     if (doYUV) printf("Perf");
     printf("\n\n");
   } else if (!quiet)
-    printf(">>>>>  JPEG %s --> %s (%s)  <<<<<\n",
+    printf(">>>>>  %d-bit JPEG (%s) --> %s (%s)  <<<<<\n", precision,
            formatName(subsamp, cs, tempStr), pixFormatStr[pf],
-           (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down");
+           bottomUp ? "Bottom-up" : "Top-down");
 
-  for (tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
+  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 ((jpegBuf = (unsigned char **)malloc(sizeof(unsigned char *) *
-                                            ntilesw * ntilesh)) == NULL)
+    if ((jpegBufs = (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)
+    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(jpegSize, 0, sizeof(unsigned long) * ntilesw * ntilesh);
+    memset(jpegSizes, 0, sizeof(size_t) * ntilesw * ntilesh);
 
-    if ((flags & TJFLAG_NOREALLOC) != 0 &&
-        (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter))
+    if (noRealloc &&
+        (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)
+        size_t jpegBufSize;
+
+        if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
+            xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270)
+          jpegBufSize = tj3JPEGBufSize(tileh, tilew, subsamp);
+        else
+          jpegBufSize = tj3JPEGBufSize(tilew, tileh, subsamp);
+        if (jpegBufSize == 0)
+          THROW_TJG();
+        if ((jpegBufs[i] = tj3Alloc(jpegBufSize)) == NULL)
           THROW_UNIX("allocating JPEG tiles");
       }
+    }
 
     tw = w;  th = h;  ttilew = tilew;  ttileh = tileh;
     if (!quiet) {
       printf("\n%s size: %d x %d", doTile ? "Tile" : "Image", ttilew, ttileh);
-      if (sf.num != 1 || sf.denom != 1)
-        printf(" --> %d x %d", TJSCALED(tw, sf), TJSCALED(th, sf));
+      if (sf.num != 1 || sf.denom != 1 || IS_CROPPED(cr))
+        printf(" --> %d x %d", CROPPED_WIDTH(tw), CROPPED_HEIGHT(th));
       printf("\n");
     } else if (quiet == 1) {
-      printf("%-4s (%s)  %-5s  %-5s    ", pixFormatStr[pf],
-             (flags & TJFLAG_BOTTOMUP) ? "BU" : "TD", csName[cs],
-             subNameLong[subsamp]);
-      printf("%-5d  %-5d   ", tilew, tileh);
+      printf("%-4s(%s)  %-14s   ", pixFormatStr[pf],
+             bottomUp ? "BU" : "TD", formatName(subsamp, cs, tempStr));
+      printf("%-5d  %-5d   ", CROPPED_WIDTH(tilew), CROPPED_HEIGHT(tileh));
     }
 
     tsubsamp = subsamp;
@@ -639,7 +768,11 @@ static int decompTest(char *fileName)
         tw = h;  th = w;  ttilew = tileh;  ttileh = tilew;
       }
 
-      if (xformOpt & TJXOPT_GRAY) tsubsamp = TJ_GRAYSCALE;
+      if (xformOp != TJXOP_NONE && xformOp != TJXOP_TRANSPOSE &&
+          subsamp == TJSAMP_UNKNOWN)
+        THROW("transforming",
+              "Could not determine subsampling level of JPEG image");
+      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)
@@ -655,6 +788,8 @@ static int decompTest(char *fileName)
           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;
       }
 
       for (row = 0, tile = 0; row < tntilesh; row++) {
@@ -666,8 +801,8 @@ static int decompTest(char *fileName)
           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;
+          if (t[tile].options & TJXOPT_NOOUTPUT && jpegBufs[tile]) {
+            tj3Free(jpegBufs[tile]);  jpegBufs[tile] = NULL;
           }
         }
       }
@@ -676,9 +811,9 @@ static int decompTest(char *fileName)
       elapsed = 0.;
       while (1) {
         start = getTime();
-        if (tjTransform(handle, srcBuf, srcSize, tntilesw * tntilesh, jpegBuf,
-                        jpegSize, t, flags) == -1)
-          THROW_TJ("executing tjTransform()");
+        if (tj3Transform(handle, srcBuf, srcSize, tntilesw * tntilesh,
+                         jpegBufs, jpegSizes, t) == -1)
+          THROW_TJ();
         elapsed += getTime() - start;
         if (iter >= 0) {
           iter++;
@@ -692,7 +827,7 @@ static int decompTest(char *fileName)
       free(t);  t = NULL;
 
       for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
-        totalJpegSize += jpegSize[tile];
+        totalJpegSize += jpegSizes[tile];
 
       if (quiet) {
         printf("%-6s%s%-6s%s",
@@ -705,7 +840,7 @@ static int decompTest(char *fileName)
         printf("Transform     --> Frame rate:         %f fps\n",
                1.0 / elapsed);
         printf("                  Output image size:  %lu bytes\n",
-               totalJpegSize);
+               (unsigned long)totalJpegSize);
         printf("                  Compression ratio:  %f:1\n",
                (double)(w * h * ps) / (double)totalJpegSize);
         printf("                  Throughput:         %f Megapixels/sec\n",
@@ -715,41 +850,41 @@ static int decompTest(char *fileName)
       }
     } else {
       if (quiet == 1) printf("N/A     N/A     ");
-      tjFree(jpegBuf[0]);
-      jpegBuf[0] = NULL;
+      tj3Free(jpegBufs[0]);
+      jpegBufs[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,
+      if (decomp(decompsrc ? &srcBuf : jpegBufs,
+                 decompsrc ? &srcSize : jpegSizes, NULL, tw, th, tsubsamp, 0,
                  fileName, ttilew, ttileh) == -1)
         goto bailout;
     } else if (quiet == 1) printf("N/A\n");
 
     for (i = 0; i < ntilesw * ntilesh; i++) {
-      tjFree(jpegBuf[i]);
-      jpegBuf[i] = NULL;
+      tj3Free(jpegBufs[i]);
+      jpegBufs[i] = NULL;
     }
-    free(jpegBuf);  jpegBuf = NULL;
-    free(jpegSize);  jpegSize = NULL;
+    free(jpegBufs);  jpegBufs = NULL;
+    free(jpegSizes);  jpegSizes = NULL;
 
     if (tilew == w && tileh == h) break;
   }
 
 bailout:
   if (file) fclose(file);
-  if (jpegBuf) {
+  if (jpegBufs) {
     for (i = 0; i < ntilesw * ntilesh; i++)
-      tjFree(jpegBuf[i]);
+      tj3Free(jpegBufs[i]);
   }
-  free(jpegBuf);
-  free(jpegSize);
+  free(jpegBufs);
+  free(jpegSizes);
   free(srcBuf);
   free(t);
-  if (handle) { tjDestroy(handle);  handle = NULL; }
+  tj3Destroy(handle);
   return retval;
 }
 
@@ -759,38 +894,63 @@ static void usage(char *progName)
   int i;
 
   printf("USAGE: %s\n", progName);
-  printf("       <Inputfile (BMP|PPM)> <Quality> [options]\n\n");
+  printf("       <Inputimage (BMP|PPM)> <Quality or PSV> [options]\n\n");
   printf("       %s\n", progName);
-  printf("       <Inputfile (JPG)> [options]\n\n");
-  printf("Options:\n\n");
-  printf("-alloc = Dynamically allocate JPEG image buffers\n");
-  printf("-bmp = Generate output images in Windows Bitmap format (default = PPM)\n");
-  printf("-bottomup = Test bottom-up compression/decompression\n");
-  printf("-tile = Test performance of the codec when the image is encoded as separate\n");
-  printf("     tiles of varying sizes.\n");
+  printf("       <Inputimage (JPG)> [options]\n");
+
+  printf("\nGENERAL OPTIONS\n");
+  printf("---------------\n");
+  printf("-alloc = Dynamically allocate JPEG buffers\n");
+  printf("-benchtime T = Run each benchmark for at least T seconds [default = 5.0]\n");
+  printf("-bmp = Use Windows Bitmap format for output images [default = PPM]\n");
+  printf("     ** 8-bit data precision only **\n");
+  printf("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers\n");
+  printf("-componly = Stop after running compression tests.  Do not test decompression.\n");
+  printf("-lossless = Generate lossless JPEG images when compressing (implies\n");
+  printf("     -subsamp 444).  PSV is the predictor selection value (1-7).\n");
+  printf("-nowrite = Do not write reference or output images (improves consistency of\n");
+  printf("     benchmark results)\n");
   printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
-  printf("     Test the specified color conversion path in the codec (default = BGR)\n");
-  printf("-cmyk = Indirectly test YCCK JPEG compression/decompression (the source\n");
-  printf("     and destination bitmaps are still RGB.  The conversion is done\n");
-  printf("     internally prior to compression or after decompression.)\n");
-  printf("-fastupsample = Use the fastest chrominance upsampling algorithm available in\n");
-  printf("     the underlying codec\n");
-  printf("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying\n");
-  printf("     codec\n");
-  printf("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the\n");
-  printf("     underlying codec\n");
-  printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
-  printf("     compression and transform operations.\n");
-  printf("-subsamp <s> = When testing JPEG compression, this option specifies the level\n");
-  printf("     of chrominance subsampling to use (<s> = 444, 422, 440, 420, 411, or\n");
-  printf("     GRAY).  The default is to test Grayscale, 4:2:0, 4:2:2, and 4:4:4 in\n");
-  printf("     sequence.\n");
+  printf("     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("-precision N = Use N-bit data precision when compressing [N is 8, 12, or 16;\n");
+  printf("     default = 8; if N is 16, then -lossless must also be specified]\n");
+  printf("     (-precision 12 implies -optimize unless -arithmetic is also specified)\n");
   printf("-quiet = Output results in tabular rather than verbose format\n");
-  printf("-yuv = Test YUV encoding/decoding functions\n");
-  printf("-yuvpad <p> = If testing YUV encoding/decoding, this specifies the number of\n");
-  printf("     bytes to which each row of each plane in the intermediate YUV image is\n");
-  printf("     padded (default = 1)\n");
-  printf("-scale M/N = Scale down the width/height of the decompressed JPEG image by a\n");
+  printf("-restart N = When compressing, add a restart marker every N MCU rows (lossy) or\n");
+  printf("     N sample rows (lossless) [default = 0 (no restart markers)].  Append 'B'\n");
+  printf("     to specify the restart marker interval in MCU blocks (lossy) or samples\n");
+  printf("     (lossless).\n");
+  printf("-stoponwarning = Immediately discontinue the current\n");
+  printf("     compression/decompression/transform operation if a warning (non-fatal\n");
+  printf("     error) occurs\n");
+  printf("-tile = Compress/transform the input image into separate JPEG tiles of varying\n");
+  printf("     sizes (useful for measuring JPEG overhead)\n");
+  printf("-warmup T = Run each benchmark for T seconds [default = 1.0] prior to starting\n");
+  printf("     the timer, in order to prime the caches and thus improve the consistency\n");
+  printf("     of the benchmark results\n");
+
+  printf("\nLOSSY JPEG OPTIONS\n");
+  printf("------------------\n");
+  printf("-arithmetic = Use arithmetic entropy coding in JPEG images generated by\n");
+  printf("     compression and transform operations (can be combined with -progressive)\n");
+  printf("-crop WxH+X+Y = Decompress only the specified region of the JPEG image, where W\n");
+  printf("     and H are the width and height of the region (0 = maximum possible width\n");
+  printf("     or height) and X and Y are the left and upper boundary of the region, all\n");
+  printf("     specified relative to the scaled image dimensions.  X must be divible by\n");
+  printf("     the scaled MCU width.\n");
+  printf("-fastdct = Use the fastest DCT/IDCT algorithm available\n");
+  printf("-fastupsample = Use the fastest chrominance upsampling algorithm available\n");
+  printf("-optimize = Use optimized baseline entropy coding in JPEG images generated by\n");
+  printf("     compession and transform operations\n");
+  printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
+  printf("     compression and transform operations (can be combined with -arithmetic;\n");
+  printf("     implies -optimize unless -arithmetic is also specified)\n");
+  printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n");
+  printf("     have an unreasonably large number of scans\n");
+  printf("-scale M/N = When decompressing, scale the width/height of the JPEG image by a\n");
   printf("     factor of M/N (M/N = ");
   for (i = 0; i < nsf; i++) {
     printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
@@ -802,40 +962,38 @@ static void usage(char *progName)
     if (i % 8 == 0 && i != 0) printf("\n     ");
   }
   printf(")\n");
+  printf("-subsamp S = When compressing, use the specified level of chrominance\n");
+  printf("     subsampling (S = 444, 422, 440, 420, 411, 441, or GRAY) [default = test\n");
+  printf("     Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]\n");
   printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n");
-  printf("     Perform the corresponding lossless transform prior to\n");
-  printf("     decompression (these options are mutually exclusive)\n");
-  printf("-grayscale = Perform lossless grayscale conversion prior to decompression\n");
-  printf("     test (can be combined with the other transforms above)\n");
+  printf("     Perform the specified lossless transform operation on the input image\n");
+  printf("     prior to decompression (these operations are mutually exclusive)\n");
+  printf("-grayscale = Transform the input image into a grayscale JPEG image prior to\n");
+  printf("     decompression (can be combined with the other transform operations above)\n");
   printf("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)\n");
-  printf("     when transforming the image.\n");
-  printf("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n");
-  printf("-warmup <t> = Run each benchmark for <t> seconds (default = 1.0) prior to\n");
-  printf("     starting the timer, in order to prime the caches and thus improve the\n");
-  printf("     consistency of the results.\n");
-  printf("-componly = Stop after running compression tests.  Do not test decompression.\n");
-  printf("-nowrite = Do not write reference or output images (improves consistency of\n");
-  printf("     performance measurements.)\n");
-  printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n");
-  printf("     have an unreasonably large number of scans\n");
-  printf("-stoponwarning = Immediately discontinue the current\n");
-  printf("     compression/decompression/transform operation if the underlying codec\n");
-  printf("     throws a warning (non-fatal error)\n\n");
-  printf("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");
+  printf("     when transforming the input image\n");
+  printf("-yuv = Compress from/decompress to intermediate planar YUV images\n");
+  printf("     ** 8-bit data precision only **\n");
+  printf("-yuvpad N = The number of bytes by which each row in each plane of an\n");
+  printf("     intermediate YUV image is evenly divisible (N must be a power of 2)\n");
+  printf("     [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);
 }
 
 
 int main(int argc, char *argv[])
 {
-  unsigned char *srcBuf = NULL;
+  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 = tjGetScalingFactors(&nsf)) == NULL || nsf == 0)
-    THROW("executing tjGetScalingFactors()", tjGetErrorStr());
+  if ((scalingFactors = tj3GetScalingFactors(&nsf)) == NULL || nsf == 0)
+    THROW("executing tj3GetScalingFactors()", tj3GetErrorStr(NULL));
 
   if (argc < minArg) usage(argv[0]);
 
@@ -851,13 +1009,9 @@ int main(int argc, char *argv[])
   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);
-    }
+    minQual = atoi(argv[2]);
     if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 &&
-        sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual &&
-        maxQual >= 1 && maxQual <= 100) {}
+        sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual) {}
     else maxQual = minQual;
   }
 
@@ -865,18 +1019,33 @@ int main(int argc, char *argv[])
     for (i = minArg; i < argc; i++) {
       if (!strcasecmp(argv[i], "-tile")) {
         doTile = 1;  xformOpt |= TJXOPT_CROP;
+      } else if (!strcasecmp(argv[i], "-precision") && i < argc - 1) {
+        int tempi = atoi(argv[++i]);
+
+        if (tempi != 8 && tempi != 12 && tempi != 16)
+          usage(argv[0]);
+        precision = tempi;
       } else if (!strcasecmp(argv[i], "-fastupsample")) {
-        printf("Using fast upsampling code\n\n");
-        flags |= TJFLAG_FASTUPSAMPLE;
+        printf("Using fastest upsampling algorithm\n\n");
+        fastUpsample = 1;
       } else if (!strcasecmp(argv[i], "-fastdct")) {
         printf("Using fastest DCT/IDCT algorithm\n\n");
-        flags |= TJFLAG_FASTDCT;
-      } else if (!strcasecmp(argv[i], "-accuratedct")) {
-        printf("Using most accurate DCT/IDCT algorithm\n\n");
-        flags |= TJFLAG_ACCURATEDCT;
+        fastDCT = 1;
+      } else if (!strcasecmp(argv[i], "-optimize")) {
+        printf("Using optimized baseline entropy coding\n\n");
+        optimize = 1;
+        xformOpt |= TJXOPT_OPTIMIZE;
       } else if (!strcasecmp(argv[i], "-progressive")) {
         printf("Using progressive entropy coding\n\n");
-        flags |= TJFLAG_PROGRESSIVE;
+        progressive = 1;
+        xformOpt |= TJXOPT_PROGRESSIVE;
+      } else if (!strcasecmp(argv[i], "-arithmetic")) {
+        printf("Using arithmetic entropy coding\n\n");
+        arithmetic = 1;
+        xformOpt |= TJXOPT_ARITHMETIC;
+      } else if (!strcasecmp(argv[i], "-lossless")) {
+        lossless = 1;
+        subsamp = TJSAMP_444;
       } else if (!strcasecmp(argv[i], "-rgb"))
         pf = TJPF_RGB;
       else if (!strcasecmp(argv[i], "-rgbx"))
@@ -892,7 +1061,7 @@ int main(int argc, char *argv[])
       else if (!strcasecmp(argv[i], "-cmyk"))
         pf = TJPF_CMYK;
       else if (!strcasecmp(argv[i], "-bottomup"))
-        flags |= TJFLAG_BOTTOMUP;
+        bottomUp = 1;
       else if (!strcasecmp(argv[i], "-quiet"))
         quiet = 1;
       else if (!strcasecmp(argv[i], "-qq"))
@@ -902,15 +1071,22 @@ int main(int argc, char *argv[])
 
         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) {
+            if (temp1 == scalingFactors[j].num &&
+                temp2 == scalingFactors[j].denom) {
               sf = scalingFactors[j];
               match = 1;  break;
             }
           }
           if (!match) usage(argv[0]);
         } else usage(argv[0]);
+      } else if (!strcasecmp(argv[i], "-crop") && i < argc - 1) {
+        int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1;
+
+        if (sscanf(argv[++i], "%dx%d+%d+%d", &temp1, &temp2, &temp3,
+                   &temp4) == 4 && temp1 >= 0 && temp2 >= 0 && temp3 >= 0 &&
+                   temp4 >= 0) {
+          cr.w = temp1;  cr.h = temp2;  cr.x = temp3;  cr.y = temp4;
+        } else usage(argv[0]);
       } else if (!strcasecmp(argv[i], "-hflip"))
         xformOp = TJXOP_HFLIP;
       else if (!strcasecmp(argv[i], "-vflip"))
@@ -945,16 +1121,17 @@ int main(int argc, char *argv[])
         else usage(argv[0]);
         printf("Warmup time = %.1f seconds\n\n", warmup);
       } else if (!strcasecmp(argv[i], "-alloc"))
-        flags &= (~TJFLAG_NOREALLOC);
+        noRealloc = 0;
       else if (!strcasecmp(argv[i], "-bmp"))
         ext = "bmp";
       else if (!strcasecmp(argv[i], "-yuv")) {
-        printf("Testing YUV planar encoding/decoding\n\n");
+        printf("Testing planar YUV encoding/decoding\n\n");
         doYUV = 1;
       } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
         int tempi = atoi(argv[++i]);
 
-        if (tempi >= 1) yuvPad = tempi;
+        if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi;
+        else usage(argv[0]);
       } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) {
         i++;
         if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY;
@@ -967,6 +1144,8 @@ int main(int argc, char *argv[])
           case 440:  subsamp = TJSAMP_440;  break;
           case 420:  subsamp = TJSAMP_420;  break;
           case 411:  subsamp = TJSAMP_411;  break;
+          case 441:  subsamp = TJSAMP_441;  break;
+          default:  usage(argv[0]);
           }
         }
       } else if (!strcasecmp(argv[i], "-componly"))
@@ -974,41 +1153,99 @@ int main(int argc, char *argv[])
       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;
+        limitScans = 1;
+      else if (!strcasecmp(argv[i], "-restart") && 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 (!strcasecmp(argv[i], "-stoponwarning"))
+        stopOnWarning = 1;
       else usage(argv[0]);
     }
   }
 
+  if (precision == 16 && !lossless) {
+    printf("ERROR: -lossless must be specified along with -precision 16\n");
+    retval = -1;  goto bailout;
+  }
+  if (precision != 8 && doYUV) {
+    printf("ERROR: -yuv requires 8-bit data precision\n");
+    retval = -1;  goto bailout;
+  }
+  if (lossless && doYUV) {
+    printf("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) {
     printf("Disabling tiled compression/decompression tests, because those tests do not\n");
-    printf("work when scaled decompression is enabled.\n");
-    doTile = 0;
+    printf("work when scaled decompression is enabled.\n\n");
+    doTile = 0;  xformOpt &= (~TJXOPT_CROP);
+  }
+
+  if (IS_CROPPED(cr)) {
+    if (!decompOnly) {
+      printf("ERROR: Partial image decompression can only be enabled for JPEG input images\n");
+      retval = -1;  goto bailout;
+    }
+    if (doTile) {
+      printf("Disabling tiled compression/decompression tests, because those tests do not\n");
+      printf("work when partial image decompression is enabled.\n\n");
+      doTile = 0;  xformOpt &= (~TJXOPT_CROP);
+    }
+    if (doYUV) {
+      printf("ERROR: -crop and -yuv are incompatible\n");
+      retval = -1;  goto bailout;
+    }
   }
 
-  if ((flags & TJFLAG_NOREALLOC) == 0 && doTile) {
+  if (!noRealloc && doTile) {
     printf("Disabling tiled compression/decompression tests, because those tests do not\n");
     printf("work when dynamic JPEG buffer allocation is enabled.\n\n");
-    doTile = 0;
+    doTile = 0;  xformOpt &= (~TJXOPT_CROP);
   }
 
   if (!decompOnly) {
-    if ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
-      THROW_TJG("loading bitmap");
+    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 (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) {
     printf("All performance values in Mpixels/sec\n\n");
-    printf("Bitmap     JPEG     JPEG  %s  %s   ",
+    printf("Pixel     JPEG      JPEG  %s  %s   ",
            doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
     if (doYUV) printf("Encode  ");
     printf("Comp    Comp    Decomp  ");
     if (doYUV) printf("Decode");
     printf("\n");
-    printf("Format     Subsamp  Qual  Width  Height  ");
+    printf("Format    Format    %s  Width  Height  ",
+           lossless ? "PSV " : "Qual");
     if (doYUV) printf("Perf    ");
     printf("Perf    Ratio   Perf    ");
     if (doYUV) printf("Perf");
@@ -1020,28 +1257,40 @@ int main(int argc, char *argv[])
     printf("\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(srcBuf, w, h, subsamp, i, argv[1]);
+      fullTest(handle, srcBuf, w, h, subsamp, i, argv[1]);
     printf("\n");
   } else {
     if (pf != TJPF_CMYK) {
       for (i = maxQual; i >= minQual; i--)
-        fullTest(srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
+        fullTest(handle, srcBuf, w, h, TJSAMP_GRAY, i, argv[1]);
       printf("\n");
     }
     for (i = maxQual; i >= minQual; i--)
-      fullTest(srcBuf, w, h, TJSAMP_420, i, argv[1]);
+      fullTest(handle, srcBuf, w, h, TJSAMP_420, i, argv[1]);
     printf("\n");
     for (i = maxQual; i >= minQual; i--)
-      fullTest(srcBuf, w, h, TJSAMP_422, i, argv[1]);
+      fullTest(handle, srcBuf, w, h, TJSAMP_422, i, argv[1]);
     printf("\n");
     for (i = maxQual; i >= minQual; i--)
-      fullTest(srcBuf, w, h, TJSAMP_444, i, argv[1]);
+      fullTest(handle, srcBuf, w, h, TJSAMP_444, i, argv[1]);
     printf("\n");
   }
 
 bailout:
-  tjFree(srcBuf);
+  tj3Destroy(handle);
+  tj3Free(srcBuf);
   return retval;
 }
index 1c08b37..4f5a972 100755 (executable)
@@ -16,20 +16,31 @@ onexit()
 runme()
 {
        echo \*\*\* $*
-       $*
+       "$@"
 }
 
 EXT=bmp
-IMAGES="vgl_5674_0098.${EXT} vgl_6434_0018a.${EXT} vgl_6548_0026a.${EXT} nightshot_iso_100.${EXT}"
+IMAGES="vgl_5674_0098.${EXT} vgl_6434_0018a.${EXT} vgl_6548_0026a.${EXT} big_tree8.${EXT}"
 IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
 OUTDIR=`mktemp -d /tmp/__tjbenchtest_output.XXXXXX`
 EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
+JAVA="@Java_JAVA_EXECUTABLE@"
+JAVAARGS="-cp $EXEDIR/java/turbojpeg.jar -Djava.library.path=$EXEDIR"
+TJBENCH=$EXEDIR/tjbench
 BMPARG=
 NSARG=
 YUVARG=
 ALLOC=0
 ALLOCARG=
-PROGARG=
+ENTROPYARG=
+JAVAARG=
+LOSSLSARG=
+LOSSLSPSV=
+TJQUAL=95
+x1SUBSAMP="444 GRAY"
+x24SUBSAMP="422 440 420 411 441"
+ALLSUBSAMP="444 422 440 420 411 441 GRAY"
+PRECISION=8
 if [ "$EXT" = "bmp" ]; then BMPARG=-bmp; fi
 
 if [ -d $OUTDIR ]; then
@@ -43,213 +54,391 @@ while [ $# -gt 0 ]; do
                NSARG=-nosmooth
                YUVARG=-yuv
 
-# NOTE: The combination of tjEncodeYUV*() and tjCompressFromYUV*() does not
-# always produce bitwise-identical results to tjCompress*() if subsampling is
+# NOTE: The combination of tj3EncodeYUV*() and tj3CompressFromYUV*() does not
+# always produce bitwise-identical results to tj3Compress*() if subsampling is
 # enabled.  In both cases, if the image width or height are not evenly
 # divisible by the MCU width/height, then the bottom and/or right edge are
 # expanded.  However, the libjpeg code performs this expansion prior to
-# downsampling, and TurboJPEG performs it in tjCompressFromYUV*(), which is
+# downsampling, and TurboJPEG performs it in tj3CompressFromYUV*(), which is
 # after downsampling.  Thus, the two will agree only if the width/height along
 # each downsampled dimension is an odd number or is evenly divisible by the MCU
 # width/height.  This disagreement basically amounts to a round-off error, but
 # there is no easy way around it, so for now, we just test the only image that
-# works.  (NOTE: nightshot_iso_100 does not suffer from the above issue, but
-# it suffers from an unrelated problem whereby the combination of
-# tjDecompressToYUV*() and tjDecodeYUV*() do not produce bitwise-identical
-# results to tjDecompress*() if decompression scaling is enabled.  This latter
-# phenomenon is not yet fully understood but is also believed to be some sort
-# of round-off error.)
+# works.  (NOTE: big_tree8 does not suffer from the above issue, but it suffers
+# from an unrelated problem whereby the combination of tj3DecompressToYUV*()
+# and tj3DecodeYUV*() do not produce bitwise-identical results to
+# tj3Decompress*() if decompression scaling is enabled.  This latter phenomenon
+# is not yet fully understood but is also believed to be some sort of round-off
+# error.)
                IMAGES="vgl_6548_0026a.${EXT}"
                ;;
        -alloc)
                ALLOCARG=-alloc
                ALLOC=1
                ;;
+       -java)
+               JAVAARG=-java
+               TJBENCH="$JAVA $JAVAARGS TJBench"
+               ;;
+       -optimize)
+               ENTROPYARG=-optimize
+               ;;
        -progressive)
-               PROGARG=-progressive
+               if [ "$ENTROPYARG" = "-arithmetic" ]; then
+                       ENTROPYARG=-progressive-arithmetic
+               else
+                       ENTROPYARG=-progressive
+               fi
+               ;;
+       -arithmetic)
+               if [ "$ENTROPYARG" = "-progressive" ]; then
+                       ENTROPYARG=-progressive-arithmetic
+               else
+                       ENTROPYARG=-arithmetic
+               fi
+               ;;
+       -lossless)
+               LOSSLSARG="-lossless"
+               LOSSLSPSV=4
+               TJQUAL=4
+               x1SUBSAMP=444
+               x24SUBSAMP=444
+               ALLSUBSAMP=444
+               ;;
+       -precision)
+               shift
+               PRECISION=$1
+               if [ $PRECISION != 8 ]; then
+                       EXT=ppm
+                       IMAGES="big_building16.${EXT}"
+                       BMPARG=
+               fi
                ;;
        esac
        shift
 done
 
-exec >$EXEDIR/tjbenchtest$YUVARG$ALLOCARG$PROGARG.log
+if [ $PRECISION = 8 -a "$YUVARG" = "" ]; then
+       if [ "$ENTROPYARG" = "-optimize" ]; then
+               IMAGES="vgl_6434_0018a.${EXT}"
+       elif [ "$ENTROPYARG" = "-progressive" ]; then
+               IMAGES="vgl_6548_0026a.${EXT}"
+       elif [ "$ENTROPYARG" = "-arithmetic" -o \
+               "$ENTROPYARG" = "-progressive-arithmetic" ]; then
+               IMAGES="big_tree8.${EXT}"
+       fi
+fi
+
+exec >$EXEDIR/tjbenchtest$JAVAARG$YUVARG$ALLOCARG$ENTROPYARG$LOSSLSARG-$PRECISION.log
+
+if [ "$ENTROPYARG" = "-progressive-arithmetic" ]; then
+       ENTROPYARG="-progressive -arithmetic"
+fi
 
 # Standard tests
 for image in $IMAGES; do
 
        cp $IMGDIR/$image $OUTDIR
        basename=`basename $image .${EXT}`
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/djpeg -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_default_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x4 -outfile $OUTDIR/${basename}_441_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 4x1 -outfile $OUTDIR/${basename}_411_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x2 -outfile $OUTDIR/${basename}_440_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct fast $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x4 -outfile $OUTDIR/${basename}_441_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 4x1 -outfile $OUTDIR/${basename}_411_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x2 -outfile $OUTDIR/${basename}_440_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       runme $EXEDIR/cjpeg -quality 95 -precision $PRECISION -dct int $ENTROPYARG $LOSSLSARG $LOSSLSPSV -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.${EXT}
+       for samp in $ALLSUBSAMP; do
                runme $EXEDIR/djpeg -dct fast -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct int -rgb $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.${EXT} $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
        done
-       for samp in 420 422; do
-               runme $EXEDIR/djpeg -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
+       for samp in $x24SUBSAMP; do
                runme $EXEDIR/djpeg -dct fast -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct int -nosmooth $BMPARG -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.${EXT} $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
        done
 
        # Compression
        for dct in accurate fast; do
-               runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -quiet -benchtime 0.01 -warmup 0 -${dct}dct $YUVARG $ALLOCARG $PROGARG
-               for samp in GRAY 420 422 444; do
-                       runme cmp $OUTDIR/${basename}_${samp}_Q95.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
+               dctarg=
+               if [ "${dct}" = "fast" ]; then
+                       dctarg=-fastdct
+               fi
+               runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -rgb -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+               if [ "$LOSSLSARG" != "-lossless" ]; then
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 440 -rgb -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 411 -rgb -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 441 -rgb -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+               fi
+               for samp in $ALLSUBSAMP; do
+                       if [ "$LOSSLSARG" = "-lossless" ]; then
+                               runme cmp $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
+                       else
+                               runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
+                       fi
                done
        done
 
-       for dct in fast accurate default; do
-               dctarg=-${dct}dct
-               if [ "${dct}" = "default" ]; then
-                       dctarg=
+       for dct in fast accurate; do
+               dctarg=
+               if [ "${dct}" = "fast" ]; then
+                       dctarg=-fastdct
                fi
 
                # Tiled compression & decompression
-               runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $PROGARG
-               for samp in GRAY 444; do
+               runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -rgb -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+               for samp in $x1SUBSAMP; do
                        if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               if [ "$LOSSLSARG" = "-lossless" ]; then
+                                       runme cmp $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT}
+                               else
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT}
+                               fi
                        else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-                                       rm $i
-                               done
+                               if [ "$LOSSLSARG" = "-lossless" ]; then
+                                       for i in $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT}; do
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q${TJQUAL}_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT}; do
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               fi
                        fi
                done
-               runme $EXEDIR/tjbench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $PROGARG
-               for samp in 420 422; do
+               runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+               if [ "$LOSSLSARG" != "-lossless" ]; then
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 440 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 411 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme $TJBENCH $OUTDIR/$image $TJQUAL -precision $PRECISION -subsamp 441 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+               fi
+               for samp in $x24SUBSAMP; do
                        if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               if [ "$LOSSLSARG" = "-lossless" ]; then
+                                       runme cmp $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT}
+                               else
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT}
+                               fi
                        else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-                                       rm $i
-                               done
+                               if [ "$LOSSLSARG" = "-lossless" ]; then
+                                       for i in $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_full.${EXT}; do
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q${TJQUAL}_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.${EXT}; do
+                                               # If the tile size is smaller than the MCU size, then there will be
+                                               # edge artifacts at the tile boundaries, so the decompressed image
+                                               # will not be identical to the untiled decompressed image.
+                                               TILESIZE=$(basename $(echo $i | sed 's/.*_//g') .${EXT})
+                                               if [ "$TILESIZE" = "8x8" ]; then
+                                                       continue
+                                               fi
+                                               if [ "$TILESIZE" = "16x16" -a \
+                                                       \( "${samp}" = "411" -o "${samp}" = "441" \) ]; then
+                                                       continue
+                                               fi
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               fi
                        fi
                done
 
                # Tiled decompression
-               for samp in GRAY 444; do
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $PROGARG
-                       if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-                       else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
-                                       rm $i
-                               done
-                       fi
-               done
-               for samp in 420 422; do
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $PROGARG
-                       if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-                       else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
-                                       rm $i
-                               done
+               if [ "$LOSSLSARG" != "-lossless" ]; then
+                       for samp in $x1SUBSAMP; do
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG
+                               if [ $ALLOC = 1 ]; then
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               fi
+                       done
+                       for samp in $x24SUBSAMP; do
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG
+                               if [ $ALLOC = 1 ]; then
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
+                                               TILESIZE=$(basename $(echo $i | sed 's/.*_//g') .${EXT})
+                                               if [ "$TILESIZE" = "8x8" ]; then
+                                                       continue
+                                               fi
+                                               if [ "$TILESIZE" = "16x16" -a \
+                                                       \( "${samp}" = "411" -o "${samp}" = "441" \) ]; then
+                                                       continue
+                                               fi
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.${EXT}
+                                               rm $i
+                                       done
+                               fi
+                       done
+               fi
+       done
+
+       # Partial decompression
+       if [ "$LOSSLSARG" != "-lossless" -a "$YUVARG" != "-yuv" ]; then
+               for samp in $ALLSUBSAMP; do
+                       CROPW8_8=103
+                       CROPL8_8=16
+                       CROPW7_8=91
+                       CROPL7_8=14
+                       if [ "${samp}" = "411" ]; then
+                               CROPW8_8=87
+                               CROPL8_8=32
+                               CROPW7_8=77
+                               CROPL7_8=28
                        fi
+                       runme $EXEDIR/djpeg -rgb -crop ${CROPW8_8}x90+${CROPL8_8}+5 $NSARG -outfile $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
+                       runme $TJBENCH $OUTDIR/${basename}_${samp}_Q${TJQUAL}.jpg -crop ${CROPW8_8}x90+${CROPL8_8}+5 -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
+                       rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_full.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
+
+                       runme $EXEDIR/djpeg -rgb -scale 7/8 -crop ${CROPW7_8}x81+${CROPL7_8}+3 $NSARG -outfile $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
+                       runme $TJBENCH $OUTDIR/${basename}_${samp}_Q${TJQUAL}.jpg -scale 7/8 -crop ${CROPW7_8}x81+${CROPL7_8}+3 -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_7_8.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
+                       rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_7_8.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
+
+                       runme $EXEDIR/djpeg -rgb -scale 1/2 -crop 40x40+0+0 $NSARG -outfile $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
+                       runme $TJBENCH $OUTDIR/${basename}_${samp}_Q${TJQUAL}.jpg -scale 1/2 -crop 40x40+0+0 -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                       runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_1_2.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
+                       rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_1_2.ppm $OUTDIR/${basename}_${samp}_scale_crop_djpeg.ppm
                done
-       done
+       fi
 
        # Scaled decompression
        for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
                scalearg=`echo $scale | sed 's/\_/\//g'`
-               for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT} $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-                       runme cmp $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT} $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT}
-                       rm $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT}
+               SCALE=$scale
+               if [ "$LOSSLSARG" = "-lossless" ]; then
+                       SCALE=full
+               fi
+               for samp in $ALLSUBSAMP; do
+                       runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT} $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
+                       if [ "$LOSSLSARG" = "-lossless" ]; then
+                               runme $TJBENCH $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}.jpg $BMPARG -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                               runme cmp $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_${SCALE}.${EXT} $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT}
+                               rm $OUTDIR/${basename}_LOSSLS_PSV${TJQUAL}_${SCALE}.${EXT}
+                       else
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q${TJQUAL}.jpg $BMPARG -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $ENTROPYARG $LOSSLSARG
+                               runme cmp $OUTDIR/${basename}_${samp}_Q${TJQUAL}_${SCALE}.${EXT} $OUTDIR/${basename}_${samp}_${scale}_djpeg.${EXT}
+                               rm $OUTDIR/${basename}_${samp}_Q${TJQUAL}_${SCALE}.${EXT}
+                       fi
                done
        done
 
        # Transforms
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/jpegtran -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-       done
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444; do
-                       runme $EXEDIR/djpeg -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-                       if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-                       else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-                                       rm $i
-                               done
-                       fi
+       if [ "$LOSSLSARG" != "-lossless" ]; then
+               for samp in $ALLSUBSAMP; do
+                       runme $EXEDIR/jpegtran -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
+                       runme $EXEDIR/jpegtran -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
                done
-               for samp in 420 422; do
-                       runme $EXEDIR/djpeg -nosmooth -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample $YUVARG $ALLOCARG $PROGARG
-                       if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-                       else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
-                                       rm $i
-                               done
-                       fi
+               for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
+                       for samp in $x1SUBSAMP; do
+                               runme $EXEDIR/djpeg -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $ENTROPYARG
+                               if [ $ALLOC = 1 ]; then
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
+                                               rm $i
+                                       done
+                               fi
+                       done
+                       for samp in $x24SUBSAMP; do
+                               runme $EXEDIR/djpeg -nosmooth -rgb $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample $YUVARG $ALLOCARG $ENTROPYARG
+                               if [ $ALLOC = 1 ]; then
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
+                                               TILESIZE=$(basename $(echo $i | sed 's/.*_//g') .${EXT})
+                                               if [ "$TILESIZE" = "8x8" ]; then
+                                                       continue
+                                               fi
+                                               if [ "$TILESIZE" = "16x16" -a \
+                                                       \( "${samp}" = "411" -o "${samp}" = "441" \) ]; then
+                                                       continue
+                                               fi
+                                               runme cmp $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.${EXT}
+                                               rm $i
+                                       done
+                               fi
+                       done
                done
-       done
 
-       # Grayscale transform
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -grayscale $YUVARG $ALLOCARG $PROGARG
-                       if [ $ALLOC = 1 ]; then
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
-                       else
-                               for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].${EXT} \
-                                       $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
-                                       runme cmp $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
-                                       rm $i
-                               done
-                       fi
+               # Grayscale transform
+               for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
+                       for samp in $ALLSUBSAMP; do
+                               runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -tile -quiet -benchtime 0.01 -warmup 0 -grayscale $YUVARG $ALLOCARG $ENTROPYARG
+                               if [ $ALLOC = 1 ]; then
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_full.${EXT} $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_full.${EXT}
+                               else
+                                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*x[0-9]*.${EXT} \
+                                               $OUTDIR/${basename}_${samp}_Q95_full.${EXT}; do
+                                               TILESIZE=$(basename $(echo $i | sed 's/.*_//g') .${EXT})
+                                               if [ "$TILESIZE" = "8x8" -a \
+                                                       "${samp}" != "444" -a "${samp}" != "GRAY" ]; then
+                                                       continue
+                                               fi
+                                               if [ "$TILESIZE" = "16x16" -a \
+                                                       \( "${samp}" = "411" -o "${samp}" = "441" \) ]; then
+                                                       continue
+                                               fi
+                                               runme cmp $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.${EXT}
+                                               rm $i
+                                       done
+                               fi
+                       done
                done
-       done
 
-       # Transforms with scaling
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-                               scalearg=`echo $scale | sed 's/\_/\//g'`
-                               runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                               runme $EXEDIR/tjbench $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $PROGARG
-                               runme cmp $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT} $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT}
-                               rm $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT}
+               # Transforms with scaling
+               for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
+                       for samp in $ALLSUBSAMP; do
+                               for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
+                                       scalearg=`echo $scale | sed 's/\_/\//g'`
+                                       runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG $BMPARG -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT} $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
+                                       runme $TJBENCH $OUTDIR/${basename}_${samp}_Q95.jpg $BMPARG -$xform -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $ALLOCARG $ENTROPYARG
+                                       runme cmp $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT} $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.${EXT}
+                                       rm $OUTDIR/${basename}_${samp}_Q95_${scale}.${EXT}
+                               done
                        done
                done
-       done
+       fi
 
 done
 
diff --git a/tjbenchtest.java.in b/tjbenchtest.java.in
deleted file mode 100755 (executable)
index 689561d..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/bin/bash
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-onexit()
-{
-       if [ -d $OUTDIR ]; then
-               rm -rf $OUTDIR
-       fi
-}
-
-runme()
-{
-       echo \*\*\* $*
-       "$@"
-}
-
-IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp nightshot_iso_100.bmp"
-IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
-OUTDIR=`mktemp -d /tmp/__tjbenchtest_java_output.XXXXXX`
-EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
-JAVA="@Java_JAVA_EXECUTABLE@"
-JAVAARGS="-cp $EXEDIR/java/turbojpeg.jar -Djava.library.path=$EXEDIR"
-BMPARG=
-NSARG=
-YUVARG=
-PROGARG=
-
-if [ -d $OUTDIR ]; then
-       rm -rf $OUTDIR
-fi
-mkdir -p $OUTDIR
-
-while [ $# -gt 0 ]; do
-       case "$1" in
-       -yuv)
-               NSARG=-nosmooth
-               YUVARG=-yuv
-
-# NOTE: The combination of tjEncodeYUV*() and tjCompressFromYUV*() does not
-# always produce bitwise-identical results to tjCompress*() if subsampling is
-# enabled.  In both cases, if the image width or height are not evenly
-# divisible by the MCU width/height, then the bottom and/or right edge are
-# expanded.  However, the libjpeg code performs this expansion prior to
-# downsampling, and TurboJPEG performs it in tjCompressFromYUV*(), which is
-# after downsampling.  Thus, the two will agree only if the width/height along
-# each downsampled dimension is an odd number or is evenly divisible by the MCU
-# width/height.  This disagreement basically amounts to a round-off error, but
-# there is no easy way around it, so for now, we just test the only image that
-# works.  (NOTE: nightshot_iso_100 does not suffer from the above issue, but
-# it suffers from an unrelated problem whereby the combination of
-# tjDecompressToYUV*() and tjDecodeYUV*() do not produce bitwise-identical
-# results to tjDecompress*() if decompression scaling is enabled.  This latter
-# phenomenon is not yet fully understood but is also believed to be some sort
-# of round-off error.)
-               IMAGES="vgl_6548_0026a.bmp"
-               ;;
-       -progressive)
-               PROGARG=-progressive
-               ;;
-       esac
-       shift
-done
-
-exec >$EXEDIR/tjbenchtest-java$YUVARG$PROGARG.log
-
-# Standard tests
-for image in $IMAGES; do
-
-       cp $IMGDIR/$image $OUTDIR
-       basename=`basename $image .bmp`
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int $PROGARG -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_default_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct fast -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct int -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-       done
-       for samp in 420 422; do
-               runme $EXEDIR/djpeg -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct fast -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct int -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-       done
-
-       # Compression
-       for dct in accurate fast; do
-               runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -quiet -benchtime 0.01 -warmup 0 -${dct}dct $YUVARG $PROGARG
-               for samp in GRAY 420 422 444; do
-                       runme cmp $OUTDIR/${basename}_${samp}_Q95.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
-               done
-       done
-
-       for dct in fast accurate default; do
-               dctarg=-${dct}dct
-               if [ "${dct}" = "default" ]; then
-                       dctarg=
-               fi
-
-               # Tiled compression & decompression
-               runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $PROGARG
-               for samp in GRAY 444; do
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
-                               rm $i
-                       done
-               done
-               runme "$JAVA" $JAVAARGS TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $PROGARG
-               for samp in 420 422; do
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
-                               rm $i
-                       done
-               done
-
-               # Tiled decompression
-               for samp in GRAY 444; do
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 -warmup 0 ${dctarg} $YUVARG $PROGARG
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
-                               rm $i
-                       done
-               done
-               for samp in 420 422; do
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample ${dctarg} $YUVARG $PROGARG
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp $i -i 54:54 $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
-                               rm $i
-                       done
-               done
-       done
-
-       # Scaled decompression
-       for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-               scalearg=`echo $scale | sed 's/\_/\//g'`
-               for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG -bmp -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp
-                       rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp
-               done
-       done
-
-       # Transforms
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/jpegtran -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-               runme $EXEDIR/jpegtran -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_Q95.jpg
-       done
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444; do
-                       runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-                               rm $i
-                       done
-               done
-               for samp in 420 422; do
-                       runme $EXEDIR/djpeg -nosmooth -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 -fastupsample $YUVARG $PROGARG
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-                               rm $i
-                       done
-               done
-       done
-
-       # Grayscale transform
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -warmup 0 -grayscale $YUVARG $PROGARG
-                       for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \
-                               $OUTDIR/${basename}_${samp}_Q95_full.bmp; do
-                               runme cmp -i 54:54 $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.bmp
-                               rm $i
-                       done
-               done
-       done
-
-       # Transforms with scaling
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-                               scalearg=`echo $scale | sed 's/\_/\//g'`
-                               runme $EXEDIR/djpeg -rgb -scale ${scalearg} $NSARG -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                               runme "$JAVA" $JAVAARGS TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -scale ${scalearg} -quiet -benchtime 0.01 -warmup 0 $YUVARG $PROGARG
-                               runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp
-                               rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp
-                       done
-               done
-       done
-
-done
-
-echo SUCCESS!
index 505c9dd..579ebe5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2022
+ * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2023
  *           D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@
   retval = -1;  goto bailout; \
 }
 
-#define THROW_TJ(action)  THROW(action, tjGetErrorStr2(tjInstance))
+#define THROW_TJ(action)  THROW(action, tj3GetErrorStr(tjInstance))
 
 #define THROW_UNIX(action)  THROW(action, strerror(errno))
 
@@ -62,7 +62,7 @@
 
 
 const char *subsampName[TJ_NUMSAMP] = {
-  "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1"
+  "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1", "4:4:1"
 };
 
 const char *colorspaceName[TJ_NUMCS] = {
@@ -149,14 +149,9 @@ static void usage(char *programName)
   printf("General Options\n");
   printf("---------------\n\n");
 
-  printf("-fastupsample = Use the fastest chrominance upsampling algorithm available in\n");
-  printf("     the underlying codec.\n\n");
+  printf("-fastupsample = Use the fastest chrominance upsampling algorithm available\n\n");
 
-  printf("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying\n");
-  printf("     codec.\n\n");
-
-  printf("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the\n");
-  printf("     underlying codec.\n\n");
+  printf("-fastdct = Use the fastest DCT/IDCT algorithm available\n\n");
 
   exit(1);
 }
@@ -164,10 +159,10 @@ static void usage(char *programName)
 
 int main(int argc, char **argv)
 {
-  tjscalingfactor scalingFactor = { 1, 1 };
+  tjscalingfactor scalingFactor = TJUNSCALED;
   int outSubsamp = -1, outQual = -1;
   tjtransform xform;
-  int flags = 0;
+  int fastUpsample = 0, fastDCT = 0;
   int width, height;
   char *inFormat, *outFormat;
   FILE *jpegFile = NULL;
@@ -175,7 +170,7 @@ int main(int argc, char **argv)
   int retval = 0, i, pixelFormat = TJPF_UNKNOWN;
   tjhandle tjInstance = NULL;
 
-  if ((scalingFactors = tjGetScalingFactors(&numScalingFactors)) == NULL)
+  if ((scalingFactors = tj3GetScalingFactors(&numScalingFactors)) == NULL)
     THROW_TJ("getting scaling factors");
   memset(&xform, 0, sizeof(tjtransform));
 
@@ -241,13 +236,10 @@ int main(int argc, char **argv)
       xform.options |= TJXOPT_CROP;
     } else if (!strcasecmp(argv[i], "-fastupsample")) {
       printf("Using fast upsampling code\n");
-      flags |= TJFLAG_FASTUPSAMPLE;
+      fastUpsample = 1;
     } else if (!strcasecmp(argv[i], "-fastdct")) {
       printf("Using fastest DCT/IDCT algorithm\n");
-      flags |= TJFLAG_FASTDCT;
-    } else if (!strcasecmp(argv[i], "-accuratedct")) {
-      printf("Using most accurate DCT/IDCT algorithm\n");
-      flags |= TJFLAG_ACCURATEDCT;
+      fastDCT = 1;
     } else usage(argv[0]);
   }
 
@@ -266,7 +258,7 @@ int main(int argc, char **argv)
     int inSubsamp, inColorspace;
     int doTransform = (xform.op != TJXOP_NONE || xform.options != 0 ||
                        xform.customFilter != NULL);
-    unsigned long jpegSize;
+    size_t jpegSize;
 
     /* Read the JPEG file into memory. */
     if ((jpegFile = fopen(argv[1], "rb")) == NULL)
@@ -276,8 +268,8 @@ int main(int argc, char **argv)
       THROW_UNIX("determining input file size");
     if (size == 0)
       THROW("determining input file size", "Input file contains no data");
-    jpegSize = (unsigned long)size;
-    if ((jpegBuf = (unsigned char *)tjAlloc(jpegSize)) == NULL)
+    jpegSize = size;
+    if ((jpegBuf = tj3Alloc(jpegSize)) == NULL)
       THROW_UNIX("allocating JPEG buffer");
     if (fread(jpegBuf, jpegSize, 1, jpegFile) < 1)
       THROW_UNIX("reading input file");
@@ -286,27 +278,37 @@ int main(int argc, char **argv)
     if (doTransform) {
       /* Transform it. */
       unsigned char *dstBuf = NULL;  /* Dynamically allocate the JPEG buffer */
-      unsigned long dstSize = 0;
+      size_t dstSize = 0;
 
-      if ((tjInstance = tjInitTransform()) == NULL)
+      if ((tjInstance = tj3Init(TJINIT_TRANSFORM)) == NULL)
         THROW_TJ("initializing transformer");
       xform.options |= TJXOPT_TRIM;
-      if (tjTransform(tjInstance, jpegBuf, jpegSize, 1, &dstBuf, &dstSize,
-                      &xform, flags) < 0) {
-        tjFree(dstBuf);
+      if (tj3Transform(tjInstance, jpegBuf, jpegSize, 1, &dstBuf, &dstSize,
+                       &xform) < 0) {
+        tj3Free(dstBuf);
         THROW_TJ("transforming input image");
       }
-      tjFree(jpegBuf);
+      tj3Free(jpegBuf);
       jpegBuf = dstBuf;
       jpegSize = dstSize;
     } else {
-      if ((tjInstance = tjInitDecompress()) == NULL)
+      if ((tjInstance = tj3Init(TJINIT_DECOMPRESS)) == NULL)
         THROW_TJ("initializing decompressor");
     }
+    if (tj3Set(tjInstance, TJPARAM_FASTUPSAMPLE, fastUpsample) < 0)
+      THROW_TJ("setting TJPARAM_FASTUPSAMPLE");
+    if (tj3Set(tjInstance, TJPARAM_FASTDCT, fastDCT) < 0)
+      THROW_TJ("setting TJPARAM_FASTDCT");
 
-    if (tjDecompressHeader3(tjInstance, jpegBuf, jpegSize, &width, &height,
-                            &inSubsamp, &inColorspace) < 0)
+    if (tj3DecompressHeader(tjInstance, jpegBuf, jpegSize) < 0)
       THROW_TJ("reading JPEG header");
+    width = tj3Get(tjInstance, TJPARAM_JPEGWIDTH);
+    height = tj3Get(tjInstance, TJPARAM_JPEGHEIGHT);
+    inSubsamp = tj3Get(tjInstance, TJPARAM_SUBSAMP);
+    inColorspace = tj3Get(tjInstance, TJPARAM_COLORSPACE);
+
+    if (tj3Get(tjInstance, TJPARAM_LOSSLESS))
+      scalingFactor = TJUNSCALED;
 
     printf("%s Image:  %d x %d pixels, %s subsampling, %s colorspace\n",
            (doTransform ? "Transformed" : "Input"), width, height,
@@ -328,25 +330,33 @@ int main(int argc, char **argv)
     /* Scaling and/or a non-JPEG output image format and/or compression options
        have been selected, so we need to decompress the input/transformed
        image. */
+    if (tj3SetScalingFactor(tjInstance, scalingFactor) < 0)
+      THROW_TJ("setting scaling factor");
     width = TJSCALED(width, scalingFactor);
     height = TJSCALED(height, scalingFactor);
     if (outSubsamp < 0)
       outSubsamp = inSubsamp;
 
     pixelFormat = TJPF_BGRX;
-    if ((imgBuf = (unsigned char *)tjAlloc(width * height *
-                                           tjPixelSize[pixelFormat])) == NULL)
+    if ((unsigned long long)width * height * tjPixelSize[pixelFormat] >
+        (unsigned long long)((size_t)-1))
+      THROW("allocating uncompressed image buffer", "Image is too large");
+    if ((imgBuf =
+         (unsigned char *)malloc(sizeof(unsigned char) * width * height *
+                                 tjPixelSize[pixelFormat])) == NULL)
       THROW_UNIX("allocating uncompressed image buffer");
 
-    if (tjDecompress2(tjInstance, jpegBuf, jpegSize, imgBuf, width, 0, height,
-                      pixelFormat, flags) < 0)
+    if (tj3Decompress8(tjInstance, jpegBuf, jpegSize, imgBuf, 0,
+                       pixelFormat) < 0)
       THROW_TJ("decompressing JPEG image");
-    tjFree(jpegBuf);  jpegBuf = NULL;
-    tjDestroy(tjInstance);  tjInstance = NULL;
+    tj3Free(jpegBuf);  jpegBuf = NULL;
+    tj3Destroy(tjInstance);  tjInstance = NULL;
   } else {
     /* Input image is not a JPEG image.  Load it into memory. */
-    if ((imgBuf = tjLoadImage(argv[1], &width, 1, &height, &pixelFormat,
-                              0)) == NULL)
+    if ((tjInstance = tj3Init(TJINIT_COMPRESS)) == NULL)
+      THROW_TJ("initializing compressor");
+    if ((imgBuf = tj3LoadImage8(tjInstance, argv[1], &width, 1, &height,
+                                &pixelFormat)) == NULL)
       THROW_TJ("loading input image");
     if (outSubsamp < 0) {
       if (pixelFormat == TJPF_GRAY)
@@ -361,7 +371,7 @@ int main(int argc, char **argv)
 
   if (!strcasecmp(outFormat, "jpg")) {
     /* Output image format is JPEG.  Compress the uncompressed image. */
-    unsigned long jpegSize = 0;
+    size_t jpegSize = 0;
 
     jpegBuf = NULL;  /* Dynamically allocate the JPEG buffer */
 
@@ -370,33 +380,40 @@ int main(int argc, char **argv)
     printf(", %s subsampling, quality = %d\n", subsampName[outSubsamp],
            outQual);
 
-    if ((tjInstance = tjInitCompress()) == NULL)
+    if (!tjInstance && (tjInstance = tj3Init(TJINIT_COMPRESS)) == NULL)
       THROW_TJ("initializing compressor");
-    if (tjCompress2(tjInstance, imgBuf, width, 0, height, pixelFormat,
-                    &jpegBuf, &jpegSize, outSubsamp, outQual, flags) < 0)
+    if (tj3Set(tjInstance, TJPARAM_SUBSAMP, outSubsamp) < 0)
+      THROW_TJ("setting TJPARAM_SUBSAMP");
+    if (tj3Set(tjInstance, TJPARAM_QUALITY, outQual) < 0)
+      THROW_TJ("setting TJPARAM_QUALITY");
+    if (tj3Set(tjInstance, TJPARAM_FASTDCT, fastDCT) < 0)
+      THROW_TJ("setting TJPARAM_FASTDCT");
+    if (tj3Compress8(tjInstance, imgBuf, width, 0, height, pixelFormat,
+                     &jpegBuf, &jpegSize) < 0)
       THROW_TJ("compressing image");
-    tjDestroy(tjInstance);  tjInstance = NULL;
+    tj3Destroy(tjInstance);  tjInstance = NULL;
 
     /* Write the JPEG image to disk. */
     if ((jpegFile = fopen(argv[2], "wb")) == NULL)
       THROW_UNIX("opening output file");
     if (fwrite(jpegBuf, jpegSize, 1, jpegFile) < 1)
       THROW_UNIX("writing output file");
-    tjDestroy(tjInstance);  tjInstance = NULL;
+    tj3Destroy(tjInstance);  tjInstance = NULL;
     fclose(jpegFile);  jpegFile = NULL;
-    tjFree(jpegBuf);  jpegBuf = NULL;
+    tj3Free(jpegBuf);  jpegBuf = NULL;
   } else {
     /* Output image format is not JPEG.  Save the uncompressed image
        directly to disk. */
     printf("\n");
-    if (tjSaveImage(argv[2], imgBuf, width, 0, height, pixelFormat, 0) < 0)
+    if (tj3SaveImage8(tjInstance, argv[2], imgBuf, width, 0, height,
+                      pixelFormat) < 0)
       THROW_TJ("saving output image");
   }
 
 bailout:
-  tjFree(imgBuf);
-  if (tjInstance) tjDestroy(tjInstance);
-  tjFree(jpegBuf);
+  tj3Free(imgBuf);
+  tj3Destroy(tjInstance);
+  tj3Free(jpegBuf);
   if (jpegFile) fclose(jpegFile);
   return retval;
 }
index 0d3047e..c56fc42 100755 (executable)
@@ -19,17 +19,34 @@ runme()
        $*
 }
 
-IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp nightshot_iso_100.bmp"
+IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp big_tree8.bmp"
 IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
 OUTDIR=`mktemp -d /tmp/__tjexampletest_output.XXXXXX`
 EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
+JAVA="@Java_JAVA_EXECUTABLE@"
+JAVAARGS="-cp $EXEDIR/java/turbojpeg.jar -Djava.library.path=$EXEDIR"
+TJEXAMPLE=$EXEDIR/tjexample
+JAVAARG=
 
 if [ -d $OUTDIR ]; then
        rm -rf $OUTDIR
 fi
 mkdir -p $OUTDIR
 
-exec >$EXEDIR/tjexampletest.log
+while [ $# -gt 0 ]; do
+       case "$1" in
+       -java)
+               JAVAARG=-java
+               TJEXAMPLE="$JAVA $JAVAARGS TJExample"
+               # The Java version of TJExample can't currently handle pixel density
+               # information, so it fails on big_tree8.bmp.
+               IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp"
+               ;;
+       esac
+       shift
+done
+
+exec >$EXEDIR/tjexampletest$JAVAARG.log
 
 for image in $IMAGES; do
 
@@ -44,39 +61,39 @@ for image in $IMAGES; do
        runme $EXEDIR/cjpeg -quality 95 -dct int -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
        runme $EXEDIR/cjpeg -quality 95 -dct int -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
        for samp in GRAY 420 422 444; do
-               runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_default_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct fast -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct int -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
        done
        for samp in 420 422; do
-               runme $EXEDIR/djpeg -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct fast -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
                runme $EXEDIR/djpeg -dct int -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
        done
 
        # Compression
        for dct in fast accurate; do
+               dctarg=
+               if [ "${dct}" = "fast" ]; then
+                       dctarg=-fastdct
+               fi
                for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/tjexample $OUTDIR/$image $OUTDIR/${basename}_${samp}_${dct}.jpg -q 95 -subsamp ${samp} -${dct}dct
+                       runme $TJEXAMPLE $OUTDIR/$image $OUTDIR/${basename}_${samp}_${dct}.jpg -q 95 -subsamp ${samp} ${dctarg}
                        runme cmp $OUTDIR/${basename}_${samp}_${dct}.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
                done
        done
 
        # Decompression
-       for dct in fast accurate default; do
-               srcdct=${dct}
-               dctarg=-${dct}dct
-               if [ "${dct}" = "default" ]; then
-                       srcdct=fast
-                       dctarg=
+       for dct in fast accurate; do
+               dctarg=
+               if [ "${dct}" = "fast" ]; then
+                       dctarg=-fastdct
                fi
                for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_${srcdct}.jpg $OUTDIR/${basename}_${samp}_${dct}.bmp ${dctarg}
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_${dct}.jpg $OUTDIR/${basename}_${samp}_${dct}.bmp ${dctarg}
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${dct}.bmp $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
                        rm $OUTDIR/${basename}_${samp}_${dct}.bmp
                done
                for samp in 420 422; do
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_${srcdct}.jpg $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp -fastupsample ${dctarg}
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_${dct}.jpg $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp -fastupsample ${dctarg}
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
                        rm $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp
                done
@@ -87,7 +104,7 @@ for image in $IMAGES; do
                scalearg=`echo $scale | sed 's/\_/\//g'`
                for samp in GRAY 420 422 444; do
                        runme $EXEDIR/djpeg -rgb -bmp -scale ${scalearg} -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${scale}.bmp -scale ${scalearg}
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${scale}.bmp -scale ${scalearg}
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${scale}.bmp $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp
                        rm $OUTDIR/${basename}_${samp}_${scale}.bmp
                done
@@ -105,16 +122,16 @@ for image in $IMAGES; do
        done
        for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
                for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -crop 70x60+16+16
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -crop 70x60+16+16
                        runme cmp $OUTDIR/${basename}_${samp}_${xform}.jpg $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
                        runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
                        rm $OUTDIR/${basename}_${samp}_${xform}.bmp
                done
                for samp in 420 422; do
                        runme $EXEDIR/djpeg -nosmooth -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16 -fastupsample
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16 -fastupsample
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
                        rm $OUTDIR/${basename}_${samp}_${xform}.bmp
                done
@@ -123,9 +140,9 @@ for image in $IMAGES; do
        # Grayscale transform
        for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
                for samp in GRAY 444 422 420; do
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -grayscale -crop 70x60+16+16
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -grayscale -crop 70x60+16+16
                        runme cmp $OUTDIR/${basename}_${samp}_${xform}.jpg $OUTDIR/${basename}_GRAY_${xform}_jpegtran.jpg
-                       runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -grayscale -crop 70x60+16+16
+                       runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -grayscale -crop 70x60+16+16
                        runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_GRAY_${xform}_jpegtran.bmp
                        rm $OUTDIR/${basename}_${samp}_${xform}.bmp
                done
@@ -137,7 +154,7 @@ for image in $IMAGES; do
                        for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
                                scalearg=`echo $scale | sed 's/\_/\//g'`
                                runme $EXEDIR/djpeg -rgb -bmp -scale ${scalearg} -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                               runme $EXEDIR/tjexample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp -$xform -scale ${scalearg} -crop 70x60+16+16
+                               runme $TJEXAMPLE $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp -$xform -scale ${scalearg} -crop 70x60+16+16
                                runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp
                                rm $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp
                        done
diff --git a/tjexampletest.java.in b/tjexampletest.java.in
deleted file mode 100755 (executable)
index d4b63bc..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-#!/bin/bash
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-onexit()
-{
-       if [ -d $OUTDIR ]; then
-               rm -rf $OUTDIR
-       fi
-}
-
-runme()
-{
-       echo \*\*\* $*
-       "$@"
-}
-
-IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp nightshot_iso_100.bmp"
-IMGDIR=@CMAKE_CURRENT_SOURCE_DIR@/testimages
-OUTDIR=`mktemp -d /tmp/__tjexampletest_java_output.XXXXXX`
-EXEDIR=@CMAKE_CURRENT_BINARY_DIR@
-JAVA="@Java_JAVA_EXECUTABLE@"
-JAVAARGS="-cp $EXEDIR/java/turbojpeg.jar -Djava.library.path=$EXEDIR"
-
-if [ -d $OUTDIR ]; then
-       rm -rf $OUTDIR
-fi
-mkdir -p $OUTDIR
-
-exec >$EXEDIR/tjexampletest-java.log
-
-for image in $IMAGES; do
-
-       cp $IMGDIR/$image $OUTDIR
-       basename=`basename $image .bmp`
-       runme $EXEDIR/cjpeg -quality 95 -dct fast -grayscale -outfile $OUTDIR/${basename}_GRAY_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast -sample 2x2 -outfile $OUTDIR/${basename}_420_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast -sample 2x1 -outfile $OUTDIR/${basename}_422_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct fast -sample 1x1 -outfile $OUTDIR/${basename}_444_fast_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int -grayscale -outfile $OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int -sample 2x2 -outfile $OUTDIR/${basename}_420_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int -sample 2x1 -outfile $OUTDIR/${basename}_422_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       runme $EXEDIR/cjpeg -quality 95 -dct int -sample 1x1 -outfile $OUTDIR/${basename}_444_accurate_cjpeg.jpg $IMGDIR/${basename}.bmp
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_default_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct fast -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_fast_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct int -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-       done
-       for samp in 420 422; do
-               runme $EXEDIR/djpeg -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct fast -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-               runme $EXEDIR/djpeg -dct int -nosmooth -bmp -outfile $OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg
-       done
-
-       # Compression
-       for dct in fast accurate; do
-               for samp in GRAY 420 422 444; do
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/$image $OUTDIR/${basename}_${samp}_${dct}.jpg -q 95 -subsamp ${samp} -${dct}dct
-                       runme cmp $OUTDIR/${basename}_${samp}_${dct}.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg
-               done
-       done
-
-       # Decompression
-       for dct in fast accurate default; do
-               srcdct=${dct}
-               dctarg=-${dct}dct
-               if [ "${dct}" = "default" ]; then
-                       srcdct=fast
-                       dctarg=
-               fi
-               for samp in GRAY 420 422 444; do
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_${srcdct}.jpg $OUTDIR/${basename}_${samp}_${dct}.bmp ${dctarg}
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${dct}.bmp $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp
-                       rm $OUTDIR/${basename}_${samp}_${dct}.bmp
-               done
-               for samp in 420 422; do
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_${srcdct}.jpg $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp -fastupsample ${dctarg}
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp
-                       rm $OUTDIR/${basename}_${samp}_${dct}_nosmooth.bmp
-               done
-       done
-
-       # Scaled decompression
-       for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-               scalearg=`echo $scale | sed 's/\_/\//g'`
-               for samp in GRAY 420 422 444; do
-                       runme $EXEDIR/djpeg -rgb -bmp -scale ${scalearg} -outfile $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${scale}.bmp -scale ${scalearg}
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${scale}.bmp $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp
-                       rm $OUTDIR/${basename}_${samp}_${scale}.bmp
-               done
-       done
-
-       # Transforms
-       for samp in GRAY 420 422 444; do
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -flip horizontal -trim -outfile $OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -flip vertical -trim -outfile $OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -transpose -trim -outfile $OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -transverse -trim -outfile $OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -rotate 90 -trim -outfile $OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -rotate 180 -trim -outfile $OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-               runme $EXEDIR/jpegtran -crop 70x60+16+16 -rotate 270 -trim -outfile $OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg $OUTDIR/${basename}_${samp}_fast.jpg
-       done
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 420 422 444; do
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -crop 70x60+16+16
-                       runme cmp $OUTDIR/${basename}_${samp}_${xform}.jpg $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme $EXEDIR/djpeg -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-                       rm $OUTDIR/${basename}_${samp}_${xform}.bmp
-               done
-               for samp in 420 422; do
-                       runme $EXEDIR/djpeg -nosmooth -rgb -bmp -outfile $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -crop 70x60+16+16 -fastupsample
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp
-                       rm $OUTDIR/${basename}_${samp}_${xform}.bmp
-               done
-       done
-
-       # Grayscale transform
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.jpg -$xform -grayscale -crop 70x60+16+16
-                       runme cmp $OUTDIR/${basename}_${samp}_${xform}.jpg $OUTDIR/${basename}_GRAY_${xform}_jpegtran.jpg
-                       runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}.bmp -$xform -grayscale -crop 70x60+16+16
-                       runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}.bmp $OUTDIR/${basename}_GRAY_${xform}_jpegtran.bmp
-                       rm $OUTDIR/${basename}_${samp}_${xform}.bmp
-               done
-       done
-
-       # Transforms with scaling
-       for xform in hflip vflip transpose transverse rot90 rot180 rot270; do
-               for samp in GRAY 444 422 420; do
-                       for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do
-                               scalearg=`echo $scale | sed 's/\_/\//g'`
-                               runme $EXEDIR/djpeg -rgb -bmp -scale ${scalearg} -outfile $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg
-                               runme "$JAVA" $JAVAARGS TJExample $OUTDIR/${basename}_${samp}_fast.jpg $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp -$xform -scale ${scalearg} -crop 70x60+16+16
-                               runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp
-                               rm $OUTDIR/${basename}_${samp}_${xform}_${scale}.bmp
-                       done
-               done
-       done
-
-done
-
-echo SUCCESS!
index a7a7d09..f95b51a 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C)2009-2014, 2017-2019, 2022 D. R. Commander.
- *                                         All Rights Reserved.
+ * Copyright (C)2009-2014, 2017-2019, 2022-2023 D. R. Commander.
+ *                                              All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
 #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"
+#include "jconfigint.h"
 #ifdef _WIN32
 #include <time.h>
+#include <process.h>
 #define random()  rand()
+#define getpid()  _getpid()
 #else
 #include <unistd.h>
 #endif
@@ -55,20 +58,24 @@ static void usage(char *progName)
 {
   printf("\nUSAGE: %s [options]\n\n", progName);
   printf("Options:\n");
-  printf("-yuv = test YUV encoding/decoding support\n");
-  printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
-  printf("            4-byte boundary\n");
-  printf("-alloc = test automatic buffer allocation\n");
-  printf("-bmp = tjLoadImage()/tjSaveImage() unit test\n\n");
+  printf("-yuv = test YUV encoding/compression/decompression/decoding\n");
+  printf("       (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 is 8, 12, or 16; default is 8; if N\n");
+  printf("               is 16, 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);
 }
 
 
-#define THROW_TJ() { \
-  printf("TurboJPEG ERROR:\n%s\n", tjGetErrorStr()); \
+#define THROW_TJ(handle) { \
+  printf("TurboJPEG ERROR:\n%s\n", tj3GetErrorStr(handle)); \
   BAILOUT() \
 }
-#define TRY_TJ(f) { if ((f) == -1) THROW_TJ(); }
+#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) { \
   printf("\n%s has an MD5 sum of %s.\n   Should be %s.\n", filename, md5sum, \
@@ -77,10 +84,10 @@ static void usage(char *progName)
 }
 
 const char *subNameLong[TJ_NUMSAMP] = {
-  "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
+  "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
 };
 const char *subName[TJ_NUMSAMP] = {
-  "444", "422", "420", "GRAY", "440", "411"
+  "444", "422", "420", "GRAY", "440", "411", "441"
 };
 
 const char *pixFormatStr[TJ_NUMPF] = {
@@ -88,67 +95,79 @@ const char *pixFormatStr[TJ_NUMPF] = {
   "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
 };
 
-const int _3byteFormats[] = { TJPF_RGB, TJPF_BGR };
-const int _4byteFormats[] = {
+const int _3sampleFormats[] = { TJPF_RGB, TJPF_BGR };
+const int _4sampleFormats[] = {
   TJPF_RGBX, TJPF_BGRX, TJPF_XBGR, TJPF_XRGB, TJPF_CMYK
 };
 const int _onlyGray[] = { TJPF_GRAY };
 const int _onlyRGB[] = { TJPF_RGB };
 
-int doYUV = 0, alloc = 0, pad = 4;
+int doYUV = 0, lossless = 0, psv = 1, alloc = 0, yuvAlign = 4;
+int precision = 8, sampleSize, maxSample, tolerance, redToY, yellowToY;
 
 int exitStatus = 0;
 #define BAILOUT() { exitStatus = -1;  goto bailout; }
 
 
-static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
+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 index, row, col, halfway = 16;
+  int i, index, row, col, halfway = 16;
 
   if (pf == TJPF_GRAY) {
-    memset(buf, 0, w * h * ps);
+    memset(buf, 0, w * h * ps * sampleSize);
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
-        if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
+        if (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;
+          setVal(buf, index, (row < halfway) ? maxSample : 0);
+        else setVal(buf, index, (row < halfway) ? redToY : yellowToY);
       }
     }
   } else if (pf == TJPF_CMYK) {
-    memset(buf, 255, w * h * ps);
+    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 (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * 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) buf[index * ps + 3] = 0;
+          if (row >= halfway) setVal(buf, index * ps + 3, 0);
         } else {
-          buf[index * ps + 2] = 0;
-          if (row < halfway) buf[index * ps + 1] = 0;
+          setVal(buf, index * ps + 2, 0);
+          if (row < halfway) setVal(buf, index * ps + 1, 0);
         }
       }
     }
   } else {
-    memset(buf, 0, w * h * ps);
+    memset(buf, 0, w * h * ps * sampleSize);
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
-        if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * 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) {
-            buf[index * ps + roffset] = 255;
-            buf[index * ps + goffset] = 255;
-            buf[index * ps + boffset] = 255;
+            setVal(buf, index * ps + roffset, maxSample);
+            setVal(buf, index * ps + goffset, maxSample);
+            setVal(buf, index * ps + boffset, maxSample);
           }
         } else {
-          buf[index * ps + roffset] = 255;
-          if (row >= halfway) buf[index * ps + goffset] = 255;
+          setVal(buf, index * ps + roffset, maxSample);
+          if (row >= halfway) setVal(buf, index * ps + goffset, maxSample);
         }
       }
     }
@@ -157,7 +176,7 @@ static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
 
 
 #define CHECKVAL(v, cv) { \
-  if (v < cv - 1 || v > cv + 1) { \
+  if (v < cv - tolerance || v > cv + tolerance) { \
     printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, row, col, cv, \
            v); \
     retval = 0;  exitStatus = -1;  goto bailout; \
@@ -165,22 +184,33 @@ static void initBuf(unsigned char *buf, int w, int h, int pf, int flags)
 }
 
 #define CHECKVAL0(v) { \
-  if (v > 1) { \
+  if (v > tolerance) { \
     printf("\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) { \
-    printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, row, col, v); \
+#define CHECKVALMAX(v) { \
+  if (v < maxSample - tolerance) { \
+    printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, row, col, \
+           maxSample, 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)
+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];
@@ -196,22 +226,22 @@ static int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
   if (pf == TJPF_CMYK) {
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
-        unsigned char c, m, y, k;
+        int c, m, y, k;
 
-        if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
+        if (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];
+        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) {
-          CHECKVAL255(c);  CHECKVAL255(m);  CHECKVAL255(y);
-          if (row < halfway) CHECKVAL255(k)
+          CHECKVALMAX(c);  CHECKVALMAX(m);  CHECKVALMAX(y);
+          if (row < halfway) CHECKVALMAX(k)
           else CHECKVAL0(k)
         } else {
-          CHECKVAL255(c);  CHECKVAL0(y);  CHECKVAL255(k);
+          CHECKVALMAX(c);  CHECKVAL0(y);  CHECKVALMAX(k);
           if (row < halfway) CHECKVAL0(m)
-          else CHECKVAL255(m)
+          else CHECKVALMAX(m)
         }
       }
     }
@@ -220,36 +250,37 @@ static int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
 
   for (row = 0; row < h; row++) {
     for (col = 0; col < w; col++) {
-      unsigned char r, g, b, a;
+      int r, g, b, a;
 
-      if (flags & TJFLAG_BOTTOMUP) index = (h - row - 1) * w + col;
+      if (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;
+      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) {
-          CHECKVAL255(r);  CHECKVAL255(g);  CHECKVAL255(b);
+          CHECKVALMAX(r);  CHECKVALMAX(g);  CHECKVALMAX(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);
+            CHECKVAL(r, redToY);  CHECKVAL(g, redToY);  CHECKVAL(b, redToY);
           } else {
-            CHECKVAL(r, 226);  CHECKVAL(g, 226);  CHECKVAL(b, 226);
+            CHECKVAL(r, yellowToY);  CHECKVAL(g, yellowToY);
+            CHECKVAL(b, yellowToY);
           }
         } else {
           if (row < halfway) {
-            CHECKVAL255(r);  CHECKVAL0(g);  CHECKVAL0(b);
+            CHECKVALMAX(r);  CHECKVAL0(g);  CHECKVAL0(b);
           } else {
-            CHECKVAL255(r);  CHECKVAL255(g);  CHECKVAL0(b);
+            CHECKVALMAX(r);  CHECKVALMAX(g);  CHECKVAL0(b);
           }
         }
       }
-      CHECKVAL255(a);
+      CHECKVALMAX(a);
     }
   }
 
@@ -258,13 +289,15 @@ bailout:
     for (row = 0; row < h; row++) {
       for (col = 0; col < w; col++) {
         if (pf == TJPF_CMYK)
-          printf("%.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]);
+          printf("%.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
-          printf("%.3d/%.3d/%.3d ", buf[(row * w + col) * ps + roffset],
-                 buf[(row * w + col) * ps + goffset],
-                 buf[(row * w + col) * ps + boffset]);
+          printf("%.3d/%.3d/%.3d ",
+                 getVal(buf, (row * w + col) * ps + roffset),
+                 getVal(buf, (row * w + col) * ps + goffset),
+                 getVal(buf, (row * w + col) * ps + boffset));
       }
       printf("\n");
     }
@@ -282,7 +315,7 @@ static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
   int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
   int pw = PAD(w, hsf), ph = PAD(h, vsf);
   int cw = pw / hsf, ch = ph / vsf;
-  int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad);
+  int ypitch = PAD(pw, yuvAlign), uvpitch = PAD(cw, yuvAlign);
   int retval = 1;
   int halfway = 16 * sf.num / sf.denom;
   int blocksize = 8 * sf.num / sf.denom;
@@ -292,11 +325,11 @@ static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
       unsigned char y = buf[ypitch * row + col];
 
       if (((row / blocksize) + (col / blocksize)) % 2 == 0) {
-        if (row < halfway) CHECKVAL255(y)
+        if (row < halfway) CHECKVALMAX(y)
         else CHECKVAL0(y);
       } else {
         if (row < halfway) CHECKVAL(y, 76)
-        else CHECKVAL(y, 226);
+        else CHECKVAL(y, 225);
       }
     }
   }
@@ -312,7 +345,7 @@ static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
           CHECKVAL(u, 128);  CHECKVAL(v, 128);
         } else {
           if (row < halfway) {
-            CHECKVAL(u, 85);  CHECKVAL255(v);
+            CHECKVAL(u, 85);  CHECKVALMAX(v);
           } else {
             CHECKVAL0(u);  CHECKVAL(v, 149);
           }
@@ -347,8 +380,7 @@ bailout:
 }
 
 
-static void writeJPEG(unsigned char *jpegBuf, unsigned long jpegSize,
-                      char *filename)
+static void writeJPEG(unsigned char *jpegBuf, size_t jpegSize, char *filename)
 {
   FILE *file = fopen(filename, "wb");
 
@@ -368,55 +400,75 @@ bailout:
 }
 
 
-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)
+static void compTest(tjhandle handle, unsigned char **dstBuf, size_t *dstSize,
+                     int w, int h, int pf, char *basename)
 {
   char tempStr[1024];
-  unsigned char *srcBuf = NULL, *yuvBuf = NULL;
+  void *srcBuf = NULL;
+  unsigned char *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);
+  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 (!alloc) flags |= TJFLAG_NOREALLOC;
   if (doYUV) {
-    unsigned long yuvSize = tjBufSizeYUV2(w, pad, h, subsamp);
+    size_t yuvSize = tj3YUVBufSize(w, yuvAlign, h, subsamp);
     tjscalingfactor sf = { 1, 1 };
-    tjhandle handle2 = tjInitCompress();
+    tjhandle handle2 = NULL;
 
-    if (!handle2) THROW_TJ();
+    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);
 
     printf("%s %s -> YUV %s ... ", pfStr, buStrLong, subNameLong[subsamp]);
-    TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
-                        flags));
-    tjDestroy(handle2);
+    TRY_TJ(handle2, tj3EncodeYUV8(handle2, (unsigned char *)srcBuf, w, 0, h,
+                                  pf, yuvBuf, yuvAlign));
+    tj3Destroy(handle2);
     if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) printf("Passed.\n");
     else printf("FAILED!\n");
 
     printf("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], buStrLong,
            jpegQual);
-    TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf,
-                             dstSize, jpegQual, flags));
+    TRY_TJ(handle, tj3CompressFromYUV8(handle, yuvBuf, w, yuvAlign, h, dstBuf,
+                                       dstSize));
   } else {
-    printf("%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp],
-           jpegQual);
-    TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
-                       jpegQual, flags));
+    if (lossless)
+      printf("%s %s -> LOSSLESS PSV%d ... ", pfStr, buStrLong, jpegPSV);
+    else
+      printf("%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));
+    }
   }
 
-  SNPRINTF(tempStr, 1024, "%s_enc_%s_%s_%s_Q%d.jpg", basename, pfStr, buStr,
-           subName[subsamp], jpegQual);
+  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);
   printf("Done.\n  Result in %s\n", tempStr);
 
@@ -427,32 +479,42 @@ bailout:
 
 
 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)
+                        size_t jpegSize, int w, int h, int pf, char *basename,
+                        int subsamp, tjscalingfactor sf)
 {
-  unsigned char *dstBuf = NULL, *yuvBuf = NULL;
-  int _hdrw = 0, _hdrh = 0, _hdrsubsamp = -1;
+  void *dstBuf = NULL;
+  unsigned char *yuvBuf = NULL;
+  int _hdrw = 0, _hdrh = 0, _hdrsubsamp;
   int scaledWidth = TJSCALED(w, sf);
   int scaledHeight = TJSCALED(h, sf);
-  unsigned long dstSize = 0;
+  size_t dstSize = 0;
+  int bottomUp = tj3Get(handle, TJPARAM_BOTTOMUP);
+
+  TRY_TJ(handle, tj3SetScalingFactor(handle, sf));
 
-  TRY_TJ(tjDecompressHeader2(handle, jpegBuf, jpegSize, &_hdrw, &_hdrh,
-                             &_hdrsubsamp));
+  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 = (unsigned char *)malloc(dstSize)) == NULL)
+  if ((dstBuf = malloc(dstSize * sampleSize)) == NULL)
     THROW("Memory allocation failure");
-  memset(dstBuf, 0, dstSize);
+  memset(dstBuf, 0, dstSize * sampleSize);
 
   if (doYUV) {
-    unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
-                                          subsamp);
-    tjhandle handle2 = tjInitDecompress();
+    size_t yuvSize = tj3YUVBufSize(scaledWidth, yuvAlign, scaledHeight,
+                                   subsamp);
+    tjhandle handle2 = NULL;
 
-    if (!handle2) THROW_TJ();
+    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");
@@ -462,28 +524,37 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
     if (sf.num != 1 || sf.denom != 1)
       printf("%d/%d ... ", sf.num, sf.denom);
     else printf("... ");
-    TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth,
-                              pad, scaledHeight, flags));
+    TRY_TJ(handle, tj3DecompressToYUV8(handle, jpegBuf, jpegSize, yuvBuf,
+                                       yuvAlign));
     if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
       printf("Passed.\n");
     else printf("FAILED!\n");
 
     printf("YUV %s -> %s %s ... ", subNameLong[subsamp], pixFormatStr[pf],
-           (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
-    TRY_TJ(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
-                       scaledHeight, pf, flags));
-    tjDestroy(handle2);
+           bottomUp ? "Bottom-Up" : "Top-Down ");
+    TRY_TJ(handle2, tj3DecodeYUV8(handle2, yuvBuf, yuvAlign,
+                                  (unsigned char *)dstBuf, scaledWidth, 0,
+                                  scaledHeight, pf));
+    tj3Destroy(handle2);
   } else {
     printf("JPEG -> %s %s ", pixFormatStr[pf],
-           (flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
+           bottomUp ? "Bottom-Up" : "Top-Down ");
     if (sf.num != 1 || sf.denom != 1)
       printf("%d/%d ... ", sf.num, sf.denom);
     else printf("... ");
-    TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
-                         scaledHeight, pf, flags));
+    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, flags))
+  if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, bottomUp))
     printf("Passed.");
   else printf("FAILED!");
   printf("\n");
@@ -495,22 +566,29 @@ bailout:
 
 
 static void decompTest(tjhandle handle, unsigned char *jpegBuf,
-                       unsigned long jpegSize, int w, int h, int pf,
-                       char *basename, int subsamp, int flags)
+                       size_t jpegSize, int w, int h, int pf, char *basename,
+                       int subsamp)
 {
   int i, n = 0;
-  tjscalingfactor *sf = tjGetScalingFactors(&n);
+  tjscalingfactor *sf = NULL;
+
+  if (lossless) {
+    _decompTest(handle, jpegBuf, jpegSize, w, h, pf, basename, subsamp,
+                TJUNSCALED);
+    return;
+  }
 
-  if (!sf || !n) THROW_TJ();
+  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 && sf[i].num == 1 &&
+        ((subsamp == TJSAMP_411 || subsamp == TJSAMP_441) && sf[i].num == 1 &&
          (sf[i].denom == 2 || sf[i].denom == 1)) ||
-        (subsamp != TJSAMP_411 && sf[i].num == 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,
-                  flags, sf[i]);
+                  sf[i]);
   }
 
 bailout:
@@ -523,35 +601,47 @@ static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
 {
   tjhandle chandle = NULL, dhandle = NULL;
   unsigned char *dstBuf = NULL;
-  unsigned long size = 0;
+  size_t size = 0;
   int pfi, pf, i;
 
+  if (lossless && subsamp != TJSAMP_GRAY)
+    subsamp = TJSAMP_444;
+
   if (!alloc)
-    size = tjBufSize(w, h, subsamp);
+    size = tj3JPEGBufSize(w, h, subsamp);
   if (size != 0)
-    if ((dstBuf = (unsigned char *)tjAlloc(size)) == NULL)
+    if ((dstBuf = (unsigned char *)tj3Alloc(size)) == NULL)
       THROW("Memory allocation failure.");
 
-  if ((chandle = tjInitCompress()) == NULL ||
-      (dhandle = tjInitDecompress()) == NULL)
-    THROW_TJ();
+  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++) {
-      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;
+      TRY_TJ(chandle, tj3Set(chandle, TJPARAM_BOTTOMUP, i == 1));
+      TRY_TJ(dhandle, tj3Set(dhandle, TJPARAM_BOTTOMUP, i == 1));
       pf = formats[pfi];
-      compTest(chandle, &dstBuf, &size, w, h, pf, basename, subsamp, 100,
-               flags);
-      decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp, flags);
+      compTest(chandle, &dstBuf, &size, w, h, pf, basename);
+      decompTest(dhandle, dstBuf, size, w, h, pf, basename, subsamp);
       if (pf >= TJPF_RGBX && pf <= TJPF_XRGB) {
         printf("\n");
         decompTest(dhandle, dstBuf, size, w, h, pf + (TJPF_RGBA - TJPF_RGBX),
-                   basename, subsamp, flags);
+                   basename, subsamp);
       }
       printf("\n");
     }
@@ -559,42 +649,74 @@ static void doTest(int w, int h, const int *formats, int nformats, int subsamp,
   printf("--------------------\n\n");
 
 bailout:
-  if (chandle) tjDestroy(chandle);
-  if (dhandle) tjDestroy(dhandle);
-  tjFree(dstBuf);
+  tj3Destroy(chandle);
+  tj3Destroy(dhandle);
+  tj3Free(dstBuf);
 }
 
 
 #if SIZEOF_SIZE_T == 8
 #define CHECKSIZE(function) { \
-  if ((unsigned long long)size < (unsigned long long)0xFFFFFFFF) \
+  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 != (unsigned long)(-1) || \
-      !strcmp(tjGetErrorStr2(NULL), "No error")) \
+  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"); \
+}
 
 static void overflowTest(void)
 {
   /* Ensure that the various buffer size functions don't overflow */
-  unsigned long size;
-
-  size = tjBufSize(26755, 26755, TJSAMP_444);
-  CHECKSIZE(tjBufSize());
-  size = TJBUFSIZE(26755, 26755);
-  CHECKSIZE(TJBUFSIZE());
-  size = tjBufSizeYUV2(37838, 1, 37838, 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());
+  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;
@@ -604,71 +726,98 @@ bailout:
 static void bufSizeTest(void)
 {
   int w, h, i, subsamp;
-  unsigned char *srcBuf = NULL, *dstBuf = NULL;
+  void *srcBuf = NULL;
+  unsigned char *dstBuf = NULL;
   tjhandle handle = NULL;
-  unsigned long dstSize = 0;
+  size_t dstSize = 0;
+  int numSamp = TJ_NUMSAMP;
+
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    THROW_TJ(NULL);
 
-  if ((handle = tjInitCompress()) == NULL) THROW_TJ();
+  TRY_TJ(handle, tj3Set(handle, TJPARAM_NOREALLOC, !alloc));
+  if (lossless) {
+    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));
 
   printf("Buffer size regression test\n");
-  for (subsamp = 0; subsamp < TJ_NUMSAMP; subsamp++) {
+  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) printf("%.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)
+        if ((srcBuf = malloc(w * h * 4 * sampleSize)) == NULL)
           THROW("Memory allocation failure");
         if (!alloc || doYUV) {
-          if (doYUV) dstSize = tjBufSizeYUV2(w, pad, h, subsamp);
-          else dstSize = tjBufSize(w, h, subsamp);
-          if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
+          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) srcBuf[i] = 0;
-          else srcBuf[i] = 255;
+          if (random() < RAND_MAX / 2) setVal(srcBuf, i, 0);
+          else setVal(srcBuf, i, maxSample);
         }
 
         if (doYUV) {
-          TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
-                              subsamp, 0));
+          TRY_TJ(handle, tj3EncodeYUV8(handle, (unsigned char *)srcBuf, w, 0,
+                                       h, TJPF_BGRX, dstBuf, yuvAlign));
         } else {
-          TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
-                             &dstSize, subsamp, 100,
-                             alloc ? 0 : TJFLAG_NOREALLOC));
+          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) {
-          tjFree(dstBuf);  dstBuf = NULL;
+          tj3Free(dstBuf);  dstBuf = NULL;
         }
 
-        if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
+        if ((srcBuf = malloc(h * w * 4 * sampleSize)) == NULL)
           THROW("Memory allocation failure");
         if (!alloc || doYUV) {
-          if (doYUV) dstSize = tjBufSizeYUV2(h, pad, w, subsamp);
-          else dstSize = tjBufSize(h, w, subsamp);
-          if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
+          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) srcBuf[i] = 0;
-          else srcBuf[i] = 255;
+          if (random() < RAND_MAX / 2) setVal(srcBuf, i, 0);
+          else setVal(srcBuf, i, maxSample);
         }
 
         if (doYUV) {
-          TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
-                              subsamp, 0));
+          TRY_TJ(handle, tj3EncodeYUV8(handle, (unsigned char *)srcBuf, h, 0,
+                                       w, TJPF_BGRX, dstBuf, yuvAlign));
         } else {
-          TRY_TJ(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
-                             &dstSize, subsamp, 100,
-                             alloc ? 0 : TJFLAG_NOREALLOC));
+          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) {
-          tjFree(dstBuf);  dstBuf = NULL;
+          tj3Free(dstBuf);  dstBuf = NULL;
         }
       }
     }
@@ -677,47 +826,78 @@ static void bufSizeTest(void)
 
 bailout:
   free(srcBuf);
-  tjFree(dstBuf);
-  if (handle) tjDestroy(handle);
+  tj3Free(dstBuf);
+  tj3Destroy(handle);
 }
 
 
-static void initBitmap(unsigned char *buf, int width, int pitch, int height,
-                       int pf, int flags)
+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;
+  int i, j, ci;
 
   for (j = 0; j < height; j++) {
-    int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
+    int row = 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;
+      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 int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
-                     int pf, int flags, int gray2rgb)
+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];
@@ -727,38 +907,40 @@ static int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
   int i, j;
 
   for (j = 0; j < height; j++) {
-    int row = (flags & TJFLAG_BOTTOMUP) ? height - j - 1 : j;
+    int row = 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;
+      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 (buf[row * pitch + i * ps] != b)
+        if (getVal(buf, row * pitch + i * ps) != b)
           return 0;
       } else if (pf == TJPF_CMYK) {
-        unsigned char rf, gf, bf;
+        int 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);
+        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 (buf[row * pitch + i * ps + roffset] != b ||
-              buf[row * pitch + i * ps + goffset] != b ||
-              buf[row * pitch + i * ps + boffset] != b)
+          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 (buf[row * pitch + i * ps + roffset] != r ||
-                   buf[row * pitch + i * ps + goffset] != g ||
-                   buf[row * pitch + i * ps + boffset] != b)
+        } 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 && buf[row * pitch + i * ps + aoffset] != 0xFF)
+        if (aoffset >= 0 &&
+            getVal(buf, row * pitch + i * ps + aoffset) != maxSample)
           return 0;
       }
     }
@@ -768,89 +950,158 @@ static int cmpBitmap(unsigned char *buf, int width, int pitch, int height,
 
 
 static int doBmpTest(const char *ext, int width, int align, int height, int pf,
-                     int flags)
+                     int bottomUp)
 {
+  tjhandle handle = NULL;
   char filename[80], *md5sum, md5buf[65];
   int ps = tjPixelSize[pf], pitch = PAD(width * ps, align), loadWidth = 0,
     loadHeight = 0, retval = 0, pixelFormat = pf;
-  unsigned char *buf = NULL;
+  void *buf = NULL;
   char *md5ref;
 
+  if ((handle = tj3Init(TJINIT_TRANSFORM)) == NULL)
+    THROW_TJ(NULL);
+  TRY_TJ(handle, tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp));
+
   if (pf == TJPF_GRAY) {
-    md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
-                                       "51976530acf75f02beddf5d21149101d";
+    if (precision == 8)
+      md5ref = !strcasecmp(ext, "ppm") ? "112c682e82ce5de1cca089e20d60000b" :
+                                         "51976530acf75f02beddf5d21149101d";
+    else if (precision == 12)
+      md5ref = "0d1895c7e6f2b2c9af6e821a655c239c";
+    else
+      md5ref = "64f3320b226ea37fb58080713b4df1b2";
   } else {
-    md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
-                                       "6d659071b9bfcdee2def22cb58ddadca";
+    if (precision == 8)
+      md5ref = !strcasecmp(ext, "ppm") ? "c0c9f772b464d1896326883a5c79c545" :
+                                         "6d659071b9bfcdee2def22cb58ddadca";
+    else if (precision == 12)
+      md5ref = "2ff5299287017502832c99718450c90a";
+    else
+      md5ref = "623f54661b928d170bd2324bc3620565";
   }
 
-  if ((buf = (unsigned char *)tjAlloc(pitch * height)) == NULL)
+  if ((buf = tj3Alloc(pitch * height * sampleSize)) == NULL)
     THROW("Could not allocate memory");
-  initBitmap(buf, width, pitch, height, pf, flags);
-
-  SNPRINTF(filename, 80, "test_bmp_%s_%d_%s.%s", pixFormatStr[pf], align,
-           (flags & TJFLAG_BOTTOMUP) ? "bu" : "td", ext);
-  TRY_TJ(tjSaveImage(filename, buf, width, pitch, height, pf, flags));
+  initBitmap(buf, width, pitch, height, pf, bottomUp);
+
+  SNPRINTF(filename, 80, "test_bmp%d_%s_%d_%s_%d.%s", precision, pixFormatStr[pf],
+           align, bottomUp ? "bu" : "td", getpid(), ext);
+  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) {
+    printf("\n   Could not determine MD5 sum of %s\n", filename);
+    retval = -1;  goto bailout;
+  }
   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();
+  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) {
     printf("\n   Image dimensions of %s are bogus\n", filename);
     retval = -1;  goto bailout;
   }
-  if (!cmpBitmap(buf, width, pitch, height, pf, flags, 0)) {
+  if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 0)) {
     printf("\n   Pixel data in %s is bogus\n", filename);
     retval = -1;  goto bailout;
   }
   if (pf == TJPF_GRAY) {
-    tjFree(buf);  buf = NULL;
+    tj3Free(buf);  buf = NULL;
     pf = TJPF_XBGR;
-    if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
-                           flags)) == NULL)
-      THROW_TJ();
+    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, flags, 1)) {
+    if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 1)) {
       printf("\n   Converting %s to RGB failed\n", filename);
       retval = -1;  goto bailout;
     }
 
-    tjFree(buf);  buf = NULL;
+    tj3Free(buf);  buf = NULL;
     pf = TJPF_CMYK;
-    if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight, &pf,
-                           flags)) == NULL)
-      THROW_TJ();
+    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, flags, 1)) {
+    if (!cmpBitmap(buf, width, pitch, height, pf, bottomUp, 1)) {
       printf("\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;
+  /* Verify that tj3LoadImage*() returns the proper "preferred" pixel format
+     for the file type. */
+  tj3Free(buf);  buf = NULL;
   pf = pixelFormat;
   pixelFormat = TJPF_UNKNOWN;
-  if ((buf = tjLoadImage(filename, &loadWidth, align, &loadHeight,
-                         &pixelFormat, flags)) == NULL)
-    THROW_TJ();
+  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)) {
-    printf("\n   tjLoadImage() returned unexpected pixel format: %s\n",
+    printf("\n   tj3LoadImage8() returned unexpected pixel format: %s\n",
            pixFormatStr[pixelFormat]);
     retval = -1;
   }
   unlink(filename);
 
 bailout:
-  tjFree(buf);
+  tj3Destroy(handle);
+  tj3Free(buf);
   if (exitStatus < 0) return exitStatus;
   return retval;
 }
@@ -862,29 +1113,31 @@ static int bmpTest(void)
 
   for (align = 1; align <= 8; align *= 2) {
     for (format = 0; format < TJ_NUMPF; format++) {
-      printf("%s Top-Down BMP (row alignment = %d bytes)  ...  ",
-             pixFormatStr[format], align);
-      if (doBmpTest("bmp", width, align, height, format, 0) == -1)
-        return -1;
-      printf("OK.\n");
+      if (precision == 8) {
+        printf("%s Top-Down BMP (row alignment = %d samples)  ...  ",
+               pixFormatStr[format], align);
+        if (doBmpTest("bmp", width, align, height, format, 0) == -1)
+          return -1;
+        printf("OK.\n");
+      }
 
-      printf("%s Top-Down PPM (row alignment = %d bytes)  ...  ",
+      printf("%s Top-Down PPM (row alignment = %d samples)  ...  ",
              pixFormatStr[format], align);
-      if (doBmpTest("ppm", width, align, height, format,
-                    TJFLAG_BOTTOMUP) == -1)
+      if (doBmpTest("ppm", width, align, height, format, 1) == -1)
         return -1;
       printf("OK.\n");
 
-      printf("%s Bottom-Up BMP (row alignment = %d bytes)  ...  ",
-             pixFormatStr[format], align);
-      if (doBmpTest("bmp", width, align, height, format, 0) == -1)
-        return -1;
-      printf("OK.\n");
+      if (precision == 8) {
+        printf("%s Bottom-Up BMP (row alignment = %d samples)  ...  ",
+               pixFormatStr[format], align);
+        if (doBmpTest("bmp", width, align, height, format, 0) == -1)
+          return -1;
+        printf("OK.\n");
+      }
 
-      printf("%s Bottom-Up PPM (row alignment = %d bytes)  ...  ",
+      printf("%s Bottom-Up PPM (row alignment = %d samples)  ...  ",
              pixFormatStr[format], align);
-      if (doBmpTest("ppm", width, align, height, format,
-                    TJFLAG_BOTTOMUP) == -1)
+      if (doBmpTest("ppm", width, align, height, format, 1) == -1)
         return -1;
       printf("OK.\n");
     }
@@ -896,7 +1149,7 @@ static int bmpTest(void)
 
 int main(int argc, char *argv[])
 {
-  int i, num4bf = 5;
+  int i, bmp = 0, num4bf = 5;
 
 #ifdef _WIN32
   srand((unsigned int)time(NULL));
@@ -904,28 +1157,56 @@ int main(int argc, char *argv[])
   if (argc > 1) {
     for (i = 1; i < argc; i++) {
       if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
-      else if (!strcasecmp(argv[i], "-noyuvpad")) pad = 1;
+      else if (!strcasecmp(argv[i], "-noyuvpad")) yuvAlign = 1;
+      else if (!strcasecmp(argv[i], "-lossless")) lossless = 1;
       else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
-      else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
-      else usage(argv[0]);
+      else if (!strcasecmp(argv[i], "-bmp")) bmp = 1;
+      else if (!strcasecmp(argv[i], "-precision") && i < argc - 1) {
+        int tempi = atoi(argv[++i]);
+
+        if (tempi != 8 && tempi != 12 && tempi != 16)
+          usage(argv[0]);
+        precision = tempi;
+        if (precision == 16) 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, _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(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");
-  doTest(41, 35, _3byteFormats, 2, TJSAMP_GRAY, "test");
-  doTest(35, 39, _4byteFormats, 4, 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");
@@ -934,9 +1215,11 @@ int main(int argc, char *argv[])
     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;
 }
index a3d878c..34fbb37 100644 (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() */
 
 
@@ -143,7 +143,7 @@ requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
         for (k = 0; k < DCTSIZE2; k++) {
           temp = qtblptr->quantval[k];
           qval = qtblptr1->quantval[k];
-          if (temp != qval) {
+          if (temp != qval && qval != 0) {
             temp *= ptr[k];
             /* The following quantization code is copied from jcdctmgr.c */
 #ifdef FAST_DIVIDE
index 0cf5f70..32186f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2022 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2023 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -26,6 +26,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <limits.h>
 #include "turbojpeg.h"
 #include "jinclude.h"
 #include <jni.h>
   jobject _excobj; \
   jstring _errstr; \
   \
-  BAILIF0(_errstr = (*env)->NewStringUTF(env, tjGetErrorStr2(handle))); \
+  BAILIF0(_errstr = (*env)->NewStringUTF(env, tj3GetErrorStr(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))); \
+                                      tj3GetErrorCode(handle))); \
   (*env)->Throw(env, _excobj); \
   goto bailout; \
 }
   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)
 {
-  jint retval = (jint)tjBufSize(width, height, jpegSubsamp);
+  size_t retval = tj3JPEGBufSize(width, height, jpegSubsamp);
 
-  if (retval == -1) THROW_ARG(tjGetErrorStr());
+  if (retval == 0) THROW_ARG(tj3GetErrorStr(NULL));
+  if (retval > (size_t)INT_MAX)
+    THROW_ARG("Image is too large");
 
 bailout:
-  return retval;
+  return (jint)retval;
 }
 
 /* TurboJPEG 1.4.x: TJ::bufSizeYUV() */
 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
-  (JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp)
+  (JNIEnv *env, jclass cls, jint width, jint align, jint height, jint subsamp)
 {
-  jint retval = (jint)tjBufSizeYUV2(width, pad, height, subsamp);
+  size_t retval = tj3YUVBufSize(width, align, height, subsamp);
 
-  if (retval == -1) THROW_ARG(tjGetErrorStr());
+  if (retval == 0) THROW_ARG(tj3GetErrorStr(NULL));
+  if (retval > (size_t)INT_MAX)
+    THROW_ARG("Image is too large");
 
 bailout:
-  return 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);
+  return (jint)retval;
 }
 
 /* TurboJPEG 1.4.x: TJ::planeSizeYUV() */
@@ -166,22 +124,23 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII
   (JNIEnv *env, jclass cls, jint componentID, jint width, jint stride,
    jint height, jint subsamp)
 {
-  jint retval = (jint)tjPlaneSizeYUV(componentID, width, stride, height,
-                                     subsamp);
+  size_t retval = tj3YUVPlaneSize(componentID, width, stride, height, subsamp);
 
-  if (retval == -1) THROW_ARG(tjGetErrorStr());
+  if (retval == 0) THROW_ARG(tj3GetErrorStr(NULL));
+  if (retval > (size_t)INT_MAX)
+    THROW_ARG("Image is too large");
 
 bailout:
-  return retval;
+  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);
+  jint retval = (jint)tj3YUVPlaneWidth(componentID, width, subsamp);
 
-  if (retval == -1) THROW_ARG(tjGetErrorStr());
+  if (retval == 0) THROW_ARG(tj3GetErrorStr(NULL));
 
 bailout:
   return retval;
@@ -191,9 +150,9 @@ bailout:
 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);
+  jint retval = (jint)tj3YUVPlaneHeight(componentID, height, subsamp);
 
-  if (retval == -1) THROW_ARG(tjGetErrorStr());
+  if (retval == 0) THROW_ARG(tj3GetErrorStr(NULL));
 
 bailout:
   return retval;
@@ -207,8 +166,8 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init
   jfieldID fid;
   tjhandle handle;
 
-  if ((handle = tjInitCompress()) == NULL)
-    THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL)
+    THROW(tj3GetErrorStr(NULL), "org/libjpegturbo/turbojpeg/TJException");
 
   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
@@ -218,21 +177,52 @@ bailout:
   return;
 }
 
+/* TurboJPEG 3: TJCompressor::set() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_set
+  (JNIEnv *env, jobject obj, jint param, jint value)
+{
+  tjhandle handle = 0;
+
+  GET_HANDLE();
+
+  if (tj3Set(handle, param, value) == -1)
+    THROW_TJ();
+
+bailout:
+  return;
+}
+
+/* TurboJPEG 3: TJCompressor::get() */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_get
+  (JNIEnv *env, jobject obj, jint param)
+{
+  tjhandle handle = 0;
+
+  GET_HANDLE();
+
+  return tj3Get(handle, param);
+
+bailout:
+  return -1;
+}
+
 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)
+  (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint precision,
+   jint x, jint y, jint width, jint pitch, jint height, jint pf,
+   jbyteArray dst)
 {
   tjhandle handle = 0;
-  unsigned long jpegSize = 0;
+  size_t jpegSize = 0;
   jsize arraySize = 0, actualPitch;
-  unsigned char *srcBuf = NULL, *jpegBuf = NULL;
+  void *srcBuf = NULL;
+  unsigned char *jpegBuf = NULL;
+  int jpegSubsamp;
 
   GET_HANDLE();
 
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
       height < 1 || pitch < 0)
-    THROW_ARG("Invalid argument in compress()");
+    THROW_ARG("Invalid argument in compress*()");
   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
     THROW_ARG("Mismatch between Java and C API");
 
@@ -240,21 +230,45 @@ static jint TJCompressor_compress
   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);
+  jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
+  if (tj3Get(handle, TJPARAM_LOSSLESS) && jpegSubsamp != TJSAMP_GRAY)
+    jpegSubsamp = TJSAMP_444;
+  else if (jpegSubsamp == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
+  jpegSize = tj3JPEGBufSize(width, height, jpegSubsamp);
   if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
     THROW_ARG("Destination buffer is not large enough");
 
-  if (ProcessSystemProperties(env) < 0) goto bailout;
+  if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
+    THROW_TJ();
 
   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();
+  if (precision == 8) {
+    if (tj3Compress8(handle, &((unsigned char *)srcBuf)[y * actualPitch +
+                                                        x * tjPixelSize[pf]],
+                     width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) {
+      SAFE_RELEASE(dst, jpegBuf);
+      SAFE_RELEASE(src, srcBuf);
+      THROW_TJ();
+    }
+  } else if (precision == 12) {
+    if (tj3Compress12(handle, &((short *)srcBuf)[y * actualPitch +
+                                                 x * tjPixelSize[pf]],
+                      width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) {
+      SAFE_RELEASE(dst, jpegBuf);
+      SAFE_RELEASE(src, srcBuf);
+      THROW_TJ();
+    }
+  } else {
+    if (tj3Compress16(handle, &((unsigned short *)srcBuf)[y * actualPitch +
+                                                          x * tjPixelSize[pf]],
+                      width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) {
+      SAFE_RELEASE(dst, jpegBuf);
+      SAFE_RELEASE(src, srcBuf);
+      THROW_TJ();
+    }
   }
 
 bailout:
@@ -263,87 +277,73 @@ bailout:
   return (jint)jpegSize;
 }
 
-/* TurboJPEG 1.3.x: TJCompressor::compress() byte source */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
+/* TurboJPEG 3: TJCompressor::compress8() byte source */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3BIIIIII_3B
   (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)
+   jint pitch, jint height, jint pf, jbyteArray dst)
 {
-  return TJCompressor_compress(env, obj, src, 1, x, y, width, pitch, height,
-                               pf, dst, jpegSubsamp, jpegQual, flags);
+  return TJCompressor_compress(env, obj, src, 1, 8, x, y, width, pitch, height,
+                               pf, dst);
 }
 
-/* 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)
+/* TurboJPEG 3: TJCompressor::compress12() */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress12
+  (JNIEnv *env, jobject obj, jshortArray src, jint x, jint y, jint width,
+   jint pitch, jint height, jint pf, jbyteArray dst)
 {
-  return TJCompressor_compress(env, obj, src, 1, 0, 0, width, pitch, height,
-                               pf, dst, jpegSubsamp, jpegQual, flags);
+  return TJCompressor_compress(env, obj, src, 1, 12, x, y, width, pitch,
+                               height, pf, dst);
 }
 
-/* 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)
+/* TurboJPEG 3: TJCompressor::compress16() */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress16
+  (JNIEnv *env, jobject obj, jshortArray src, jint x, jint y, jint width,
+   jint pitch, jint height, jint pf, jbyteArray dst)
 {
-  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;
+  return TJCompressor_compress(env, obj, src, 1, 16, x, y, width, pitch,
+                               height, pf, dst);
 }
 
-/* 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)
+/* TurboJPEG 3: TJCompressor::compress8() int source */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress8___3IIIIIII_3B
+  (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
+   jint stride, jint height, jint pf, jbyteArray dst)
 {
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
-    THROW_ARG("Invalid argument in compress()");
+    THROW_ARG("Invalid argument in compress8()");
   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);
+  return TJCompressor_compress(env, obj, src, sizeof(jint), 8, x, y, width,
+                               stride * sizeof(jint), height, pf, dst);
 
 bailout:
   return 0;
 }
 
-/* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */
-JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII
+/* TurboJPEG 3: TJCompressor::compressFromYUV8() */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV8
   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
-   jint width, jintArray jSrcStrides, jint height, jint subsamp,
-   jbyteArray dst, jint jpegQual, jint flags)
+   jint width, jintArray jSrcStrides, jint height, jbyteArray dst)
 {
   tjhandle handle = 0;
-  unsigned long jpegSize = 0;
+  size_t 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;
+  int nc = 0, i, subsamp;
 
   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 ((subsamp = tj3Get(handle, TJPARAM_SUBSAMP)) == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
+  nc = subsamp == TJSAMP_GRAY ? 1 : 3;
   if ((*env)->GetArrayLength(env, srcobjs) < nc)
     THROW_ARG("Planes array is too small for the subsampling type");
   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
@@ -351,11 +351,12 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
   if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
     THROW_ARG("Strides array is too small for the subsampling type");
 
-  jpegSize = tjBufSize(width, height, subsamp);
+  jpegSize = tj3JPEGBufSize(width, height, subsamp);
   if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
     THROW_ARG("Destination buffer is not large enough");
 
-  if (ProcessSystemProperties(env) < 0) goto bailout;
+  if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
+    THROW_TJ();
 
   (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
@@ -368,20 +369,23 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
     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);
+    size_t planeSize = tj3YUVPlaneSize(i, width, srcStrides[i], height,
+                                       subsamp);
+    int pw = tj3YUVPlaneWidth(i, width, subsamp);
 
-    if (planeSize < 0 || pw < 0)
-      THROW_ARG(tjGetErrorStr());
+    if (planeSize == 0 || pw == 0)
+      THROW_ARG(tj3GetErrorStr(NULL));
 
+    if (planeSize > (size_t)INT_MAX)
+      THROW_ARG("Source plane is too large");
     if (srcOffsets[i] < 0)
-      THROW_ARG("Invalid argument in compressFromYUV()");
-    if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
+      THROW_ARG("Invalid argument in compressFromYUV8()");
+    if (srcStrides[i] < 0 && srcOffsets[i] - (int)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)
+        srcOffsets[i] + (int)planeSize)
       THROW_ARG("Source plane is not large enough");
   }
   for (i = 0; i < nc; i++) {
@@ -391,9 +395,8 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
   }
   BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
-  if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
-                              subsamp, &jpegBuf, &jpegSize, jpegQual,
-                              flags | TJFLAG_NOREALLOC) == -1) {
+  if (tj3CompressFromYUVPlanes8(handle, srcPlanes, width, srcStrides, height,
+                                &jpegBuf, &jpegSize) == -1) {
     SAFE_RELEASE(dst, jpegBuf);
     for (i = 0; i < nc; i++)
       SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
@@ -407,10 +410,10 @@ bailout:
   return (jint)jpegSize;
 }
 
-static void TJCompressor_encodeYUV
+static void TJCompressor_encodeYUV8
   (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)
+   jintArray jDstOffsets, jintArray jDstStrides)
 {
   tjhandle handle = 0;
   jsize arraySize = 0, actualPitch;
@@ -420,18 +423,20 @@ static void TJCompressor_encodeYUV
   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;
+  int nc = 0, i, subsamp;
 
   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()");
+      height < 1 || pitch < 0)
+    THROW_ARG("Invalid argument in encodeYUV8()");
   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
     THROW_ARG("Mismatch between Java and C API");
 
+  if ((subsamp = tj3Get(handle, TJPARAM_SUBSAMP)) == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
+  nc = subsamp == TJSAMP_GRAY ? 1 : 3;
   if ((*env)->GetArrayLength(env, dstobjs) < nc)
     THROW_ARG("Planes array is too small for the subsampling type");
   if ((*env)->GetArrayLength(env, jDstOffsets) < nc)
@@ -455,20 +460,23 @@ static void TJCompressor_encodeYUV
     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);
+    size_t planeSize = tj3YUVPlaneSize(i, width, dstStrides[i], height,
+                                       subsamp);
+    int pw = tj3YUVPlaneWidth(i, width, subsamp);
 
-    if (planeSize < 0 || pw < 0)
-      THROW_ARG(tjGetErrorStr());
+    if (planeSize == 0 || pw == 0)
+      THROW_ARG(tj3GetErrorStr(NULL));
 
+    if (planeSize > (size_t)INT_MAX)
+      THROW_ARG("Destination plane is too large");
     if (dstOffsets[i] < 0)
-      THROW_ARG("Invalid argument in encodeYUV()");
-    if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
+      THROW_ARG("Invalid argument in encodeYUV8()");
+    if (dstStrides[i] < 0 && dstOffsets[i] - (int)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)
+        dstOffsets[i] + (int)planeSize)
       THROW_ARG("Destination plane is not large enough");
   }
   for (i = 0; i < nc; i++) {
@@ -478,9 +486,10 @@ static void TJCompressor_encodeYUV
   }
   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) {
+  if (tj3EncodeYUVPlanes8(handle,
+                          &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
+                          width, pitch, height, pf, dstPlanes,
+                          dstStrides) == -1) {
     SAFE_RELEASE(src, srcBuf);
     for (i = 0; i < nc; i++)
       SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
@@ -493,95 +502,30 @@ bailout:
     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
+/* TurboJPEG 3: TJCompressor::encodeYUV8() byte source */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3BIIIIII_3_3B_3I_3I
   (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)
+   jintArray jDstOffsets, jintArray jDstStrides)
 {
-  TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf,
-                         dstobjs, jDstOffsets, jDstStrides, subsamp, flags);
+  TJCompressor_encodeYUV8(env, obj, src, 1, x, y, width, pitch, height, pf,
+                          dstobjs, jDstOffsets, jDstStrides);
 }
 
-/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
+/* TurboJPEG 3: TJCompressor::encodeYUV8() int source */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV8___3IIIIIII_3_3B_3I_3I
   (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)
+   jintArray jDstOffsets, jintArray jDstStrides)
 {
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
-    THROW_ARG("Invalid argument in encodeYUV()");
+    THROW_ARG("Invalid argument in encodeYUV8()");
   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);
+  TJCompressor_encodeYUV8(env, obj, src, sizeof(jint), x, y, width,
+                          stride * sizeof(jint), height, pf, dstobjs,
+                          jDstOffsets, jDstStrides);
 
 bailout:
   return;
@@ -595,7 +539,7 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
 
   GET_HANDLE();
 
-  if (tjDestroy(handle) == -1) THROW_TJ();
+  tj3Destroy(handle);
   (*env)->SetLongField(env, obj, _fid, 0);
 
 bailout:
@@ -610,8 +554,8 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
   jfieldID fid;
   tjhandle handle;
 
-  if ((handle = tjInitDecompress()) == NULL)
-    THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
+  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL)
+    THROW(tj3GetErrorStr(NULL), "org/libjpegturbo/turbojpeg/TJException");
 
   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
@@ -621,6 +565,20 @@ bailout:
   return;
 }
 
+/* TurboJPEG 3: TJDecompressor::set() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_set
+  (JNIEnv *env, jobject obj, jint param, jint value)
+{
+  Java_org_libjpegturbo_turbojpeg_TJCompressor_set(env, obj, param, value);
+}
+
+/* TurboJPEG 3: TJDecompressor::get() */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_get
+  (JNIEnv *env, jobject obj, jint param)
+{
+  return Java_org_libjpegturbo_turbojpeg_TJCompressor_get(env, obj, param);
+}
+
 /* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */
 JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
   (JNIEnv *env, jclass cls)
@@ -632,8 +590,8 @@ JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFact
   jobject sfobj = NULL;
   jobjectArray sfjava = NULL;
 
-  if ((sf = tjGetScalingFactors(&n)) == NULL || n == 0)
-    THROW_ARG(tjGetErrorStr());
+  if ((sf = tj3GetScalingFactors(&n)) == NULL || n == 0)
+    THROW_ARG(tj3GetErrorStr(NULL));
 
   BAILIF0(sfcls = (*env)->FindClass(env,
     "org/libjpegturbo/turbojpeg/TJScalingFactor"));
@@ -658,7 +616,6 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
 {
   tjhandle handle = 0;
   unsigned char *jpegBuf = NULL;
-  int width = 0, height = 0, jpegSubsamp = -1, jpegColorspace = -1;
 
   GET_HANDLE();
 
@@ -667,61 +624,158 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
 
   BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
 
-  if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width,
-                          &height, &jpegSubsamp, &jpegColorspace) == -1) {
+  if (tj3DecompressHeader(handle, jpegBuf, (size_t)jpegSize) == -1) {
     SAFE_RELEASE(src, jpegBuf);
     THROW_TJ();
   }
 
+bailout:
   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);
+/* TurboJPEG 3: TJDecompressor::setCroppingRegion() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_setCroppingRegion
+  (JNIEnv *env, jobject obj)
+{
+  tjhandle handle = 0;
+  jclass sfcls, crcls;
+  jobject sfobj, crobj;
+  tjregion croppingRegion;
+  tjscalingfactor scalingFactor;
+
+  GET_HANDLE();
+
+  BAILIF0(sfcls = (*env)->FindClass(env,
+    "org/libjpegturbo/turbojpeg/TJScalingFactor"));
+  BAILIF0(_fid =
+          (*env)->GetFieldID(env, _cls, "scalingFactor",
+                             "Lorg/libjpegturbo/turbojpeg/TJScalingFactor;"));
+  BAILIF0(sfobj = (*env)->GetObjectField(env, obj, _fid));
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
+  scalingFactor.num = (*env)->GetIntField(env, sfobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
+  scalingFactor.denom = (*env)->GetIntField(env, sfobj, _fid);
+
+  if (tj3SetScalingFactor(handle, scalingFactor) == -1)
+    THROW_TJ();
+
+  BAILIF0(crcls = (*env)->FindClass(env, "java/awt/Rectangle"));
+  BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "croppingRegion",
+                                    "Ljava/awt/Rectangle;"));
+  BAILIF0(crobj = (*env)->GetObjectField(env, obj, _fid));
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "x", "I"));
+  croppingRegion.x = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "y", "I"));
+  croppingRegion.y = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "width", "I"));
+  croppingRegion.w = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "height", "I"));
+  croppingRegion.h = (*env)->GetIntField(env, crobj, _fid);
+
+  if (tj3SetCroppingRegion(handle, croppingRegion) == -1)
+    THROW_TJ();
 
 bailout:
-  SAFE_RELEASE(src, jpegBuf);
+  return;
 }
 
 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)
+   jint dstElementSize, int precision, jint x, jint y, jint pitch, jint pf)
 {
   tjhandle handle = 0;
   jsize arraySize = 0, actualPitch;
-  unsigned char *jpegBuf = NULL, *dstBuf = NULL;
+  unsigned char *jpegBuf = NULL;
+  void *dstBuf = NULL;
+  jclass sfcls, crcls;
+  jobject sfobj, crobj;
+  tjscalingfactor scalingFactor;
+  tjregion cr;
+  int jpegWidth, jpegHeight, scaledWidth, scaledHeight;
 
   GET_HANDLE();
 
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
-    THROW_ARG("Invalid argument in decompress()");
+    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 ((jpegWidth = tj3Get(handle, TJPARAM_JPEGWIDTH)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+  if ((jpegHeight = tj3Get(handle, TJPARAM_JPEGHEIGHT)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+
+  BAILIF0(sfcls = (*env)->FindClass(env,
+    "org/libjpegturbo/turbojpeg/TJScalingFactor"));
+  BAILIF0(_fid =
+          (*env)->GetFieldID(env, _cls, "scalingFactor",
+                             "Lorg/libjpegturbo/turbojpeg/TJScalingFactor;"));
+  BAILIF0(sfobj = (*env)->GetObjectField(env, obj, _fid));
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
+  scalingFactor.num = (*env)->GetIntField(env, sfobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
+  scalingFactor.denom = (*env)->GetIntField(env, sfobj, _fid);
+
+  if (tj3SetScalingFactor(handle, scalingFactor) == -1)
+    THROW_TJ();
+  scaledWidth = TJSCALED(jpegWidth, scalingFactor);
+  scaledHeight = TJSCALED(jpegHeight, scalingFactor);
+
+  BAILIF0(crcls = (*env)->FindClass(env, "java/awt/Rectangle"));
+  BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "croppingRegion",
+                                    "Ljava/awt/Rectangle;"));
+  BAILIF0(crobj = (*env)->GetObjectField(env, obj, _fid));
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "x", "I"));
+  cr.x = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "y", "I"));
+  cr.y = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "width", "I"));
+  cr.w = (*env)->GetIntField(env, crobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, crcls, "height", "I"));
+  cr.h = (*env)->GetIntField(env, crobj, _fid);
+  if (cr.x != 0 || cr.y != 0 || cr.w != 0 || cr.h != 0) {
+    scaledWidth = cr.w ? cr.w : scaledWidth - cr.x;
+    scaledHeight = cr.h ? cr.h : scaledHeight - cr.y;
+  }
+
+  actualPitch = (pitch == 0) ? scaledWidth * tjPixelSize[pf] : pitch;
+  arraySize = (y + scaledHeight - 1) * actualPitch +
+              (x + scaledWidth) * 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();
+  if (precision == 8) {
+    if (tj3Decompress8(handle, jpegBuf, (size_t)jpegSize,
+                       &((unsigned char *)dstBuf)[y * actualPitch +
+                                                  x * tjPixelSize[pf]],
+                       pitch, pf) == -1) {
+      SAFE_RELEASE(dst, dstBuf);
+      SAFE_RELEASE(src, jpegBuf);
+      THROW_TJ();
+    }
+  } else if (precision == 12) {
+    if (tj3Decompress12(handle, jpegBuf, (size_t)jpegSize,
+                        &((short *)dstBuf)[y * actualPitch +
+                                           x * tjPixelSize[pf]],
+                        pitch, pf) == -1) {
+      SAFE_RELEASE(dst, dstBuf);
+      SAFE_RELEASE(src, jpegBuf);
+      THROW_TJ();
+    }
+  } else {
+    if (tj3Decompress16(handle, jpegBuf, (size_t)jpegSize,
+                        &((unsigned short *)dstBuf)[y * actualPitch +
+                                                    x * tjPixelSize[pf]],
+                        pitch, pf) == -1) {
+      SAFE_RELEASE(dst, dstBuf);
+      SAFE_RELEASE(src, jpegBuf);
+      THROW_TJ();
+    }
   }
 
 bailout:
@@ -729,63 +783,54 @@ bailout:
   SAFE_RELEASE(src, jpegBuf);
 }
 
-/* TurboJPEG 1.3.x: TJDecompressor::decompress() byte destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
+/* TurboJPEG 3: TJDecompressor::decompress8() byte destination */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3BIIII
   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
-   jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
+   jint x, jint y, jint pitch, jint pf)
 {
-  TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width,
-                            pitch, height, pf, flags);
+  TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 8, x, y, pitch,
+                            pf);
 }
 
-/* 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)
+/* TurboJPEG 3: TJDecompressor::decompress12() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress12
+  (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jshortArray dst,
+   jint x, jint y, jint pitch, jint pf)
 {
-  TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width,
-                            pitch, height, pf, flags);
+  TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 12, x, y, pitch,
+                            pf);
 }
 
-/* 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)
+/* TurboJPEG 3: TJDecompressor::decompress16() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress16
+  (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jshortArray dst,
+   jint x, jint y, jint pitch, jint pf)
 {
-  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;
+  TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 16, x, y, pitch,
+                            pf);
 }
 
-/* TurboJPEG 1.2.x: TJDecompressor::decompress() int destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
+/* TurboJPEG 3: TJDecompressor::decompress8() int destination */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress8___3BI_3IIIII
   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
-   jint width, jint stride, jint height, jint pf, jint flags)
+   jint x, jint y, jint stride, jint pf)
 {
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
-    THROW_ARG("Invalid argument in decompress()");
+    THROW_ARG("Invalid argument in decompress8()");
   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);
+  TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 8, x,
+                            y, stride * sizeof(jint), pf);
 
 bailout:
   return;
 }
 
-/* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
+/* TurboJPEG 3: TJDecompressor::decompressToYUV8() */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV8
   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize,
-   jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth,
-   jintArray jDstStrides, jint desiredHeight, jint flags)
+   jobjectArray dstobjs, jintArray jDstOffsets, jintArray jDstStrides)
 {
   tjhandle handle = 0;
   unsigned char *jpegBuf = NULL;
@@ -794,38 +839,40 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
   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;
+  jclass sfcls;
+  jobject sfobj;
+  int jpegSubsamp, jpegWidth = 0, jpegHeight = 0;
+  int nc = 0, i, scaledWidth, scaledHeight;
+  tjscalingfactor scalingFactor;
 
   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");
+  if ((jpegWidth = tj3Get(handle, TJPARAM_JPEGWIDTH)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+  if ((jpegHeight = tj3Get(handle, TJPARAM_JPEGHEIGHT)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+
+  BAILIF0(sfcls = (*env)->FindClass(env,
+    "org/libjpegturbo/turbojpeg/TJScalingFactor"));
+  BAILIF0(_fid =
+          (*env)->GetFieldID(env, _cls, "scalingFactor",
+                             "Lorg/libjpegturbo/turbojpeg/TJScalingFactor;"));
+  BAILIF0(sfobj = (*env)->GetObjectField(env, obj, _fid));
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
+  scalingFactor.num = (*env)->GetIntField(env, sfobj, _fid);
+  BAILIF0(_fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
+  scalingFactor.denom = (*env)->GetIntField(env, sfobj, _fid);
+
+  if (tj3SetScalingFactor(handle, scalingFactor) == -1)
+    THROW_TJ();
+  scaledWidth = TJSCALED(jpegWidth, scalingFactor);
+  scaledHeight = TJSCALED(jpegHeight, scalingFactor);
+
+  if ((jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP)) == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
+  nc = jpegSubsamp == TJSAMP_GRAY ? 1 : 3;
 
   (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp);
   if ((*env)->ExceptionCheck(env)) goto bailout;
@@ -838,21 +885,23 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
     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);
+    size_t planeSize = tj3YUVPlaneSize(i, scaledWidth, dstStrides[i],
+                                       scaledHeight, jpegSubsamp);
+    int pw = tj3YUVPlaneWidth(i, scaledWidth, jpegSubsamp);
 
-    if (planeSize < 0 || pw < 0)
-      THROW_ARG(tjGetErrorStr());
+    if (planeSize == 0 || pw == 0)
+      THROW_ARG(tj3GetErrorStr(NULL));
 
+    if (planeSize > (size_t)INT_MAX)
+      THROW_ARG("Destination plane is too large");
     if (dstOffsets[i] < 0)
-      THROW_ARG("Invalid argument in decompressToYUV()");
-    if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
+      THROW_ARG("Invalid argument in decompressToYUV8()");
+    if (dstStrides[i] < 0 && dstOffsets[i] - (int)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)
+        dstOffsets[i] + (int)planeSize)
       THROW_ARG("Destination plane is not large enough");
   }
   for (i = 0; i < nc; i++) {
@@ -862,9 +911,8 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
   }
   BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
 
-  if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
-                              dstPlanes, desiredWidth, dstStrides,
-                              desiredHeight, flags) == -1) {
+  if (tj3DecompressToYUVPlanes8(handle, jpegBuf, (size_t)jpegSize, dstPlanes,
+                                dstStrides) == -1) {
     SAFE_RELEASE(src, jpegBuf);
     for (i = 0; i < nc; i++)
       SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
@@ -877,48 +925,10 @@ bailout:
     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
+static void TJDecompressor_decodeYUV8
   (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)
+   jintArray jSrcStrides, jarray dst, jint dstElementSize, jint x, jint y,
+   jint width, jint pitch, jint height, jint pf)
 {
   tjhandle handle = 0;
   jsize arraySize = 0, actualPitch;
@@ -928,17 +938,19 @@ static void TJDecompressor_decodeYUV
   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;
+  int nc = 0, i, subsamp;
 
   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 (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
+    THROW_ARG("Invalid argument in decodeYUV8()");
   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
     THROW_ARG("Mismatch between Java and C API");
 
+  if ((subsamp = tj3Get(handle, TJPARAM_SUBSAMP)) == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
+  nc = subsamp == TJSAMP_GRAY ? 1 : 3;
   if ((*env)->GetArrayLength(env, srcobjs) < nc)
     THROW_ARG("Planes array is too small for the subsampling type");
   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
@@ -962,20 +974,23 @@ static void TJDecompressor_decodeYUV
     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);
+    size_t planeSize = tj3YUVPlaneSize(i, width, srcStrides[i], height,
+                                       subsamp);
+    int pw = tj3YUVPlaneWidth(i, width, subsamp);
 
-    if (planeSize < 0 || pw < 0)
-      THROW_ARG(tjGetErrorStr());
+    if (planeSize == 0 || pw == 0)
+      THROW_ARG(tj3GetErrorStr(NULL));
 
+    if (planeSize > (size_t)INT_MAX)
+      THROW_ARG("Source plane is too large");
     if (srcOffsets[i] < 0)
-      THROW_ARG("Invalid argument in decodeYUV()");
-    if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
+      THROW_ARG("Invalid argument in decodeYUV8()");
+    if (srcStrides[i] < 0 && srcOffsets[i] - (int)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)
+        srcOffsets[i] + (int)planeSize)
       THROW_ARG("Source plane is not large enough");
   }
   for (i = 0; i < nc; i++) {
@@ -985,9 +1000,9 @@ static void TJDecompressor_decodeYUV
   }
   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) {
+  if (tj3DecodeYUVPlanes8(handle, srcPlanes, srcStrides,
+                          &dstBuf[y * actualPitch + x * tjPixelSize[pf]],
+                          width, pitch, height, pf) == -1) {
     SAFE_RELEASE(dst, dstBuf);
     for (i = 0; i < nc; i++)
       SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
@@ -1000,31 +1015,30 @@ bailout:
     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
+/* TurboJPEG 3: TJDecompressor::decodeYUV8() byte destination */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3BIIIIII
   (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)
+   jintArray jSrcStrides, jbyteArray dst, jint x, jint y, jint width,
+   jint pitch, jint height, jint pf)
 {
-  TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
-                           subsamp, dst, 1, x, y, width, pitch, height, pf,
-                           flags);
+  TJDecompressor_decodeYUV8(env, obj, srcobjs, jSrcOffsets, jSrcStrides, dst,
+                            1, x, y, width, pitch, height, pf);
 }
 
-/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() int destination */
-JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
+/* TurboJPEG 3: TJDecompressor::decodeYUV8() int destination */
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV8___3_3B_3I_3I_3IIIIIII
   (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)
+   jintArray jSrcStrides, jintArray dst, jint x, jint y, jint width,
+   jint stride, jint height, jint pf)
 {
   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
-    THROW_ARG("Invalid argument in decodeYUV()");
+    THROW_ARG("Invalid argument in decodeYUV8()");
   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);
+  TJDecompressor_decodeYUV8(env, obj, srcobjs, jSrcOffsets, jSrcStrides, dst,
+                            sizeof(jint), x, y, width, stride * sizeof(jint),
+                            height, pf);
 
 bailout:
   return;
@@ -1038,8 +1052,8 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
   jfieldID fid;
   tjhandle handle;
 
-  if ((handle = tjInitTransform()) == NULL)
-    THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
+  if ((handle = tj3Init(TJINIT_TRANSFORM)) == NULL)
+    THROW(tj3GetErrorStr(NULL), "org/libjpegturbo/turbojpeg/TJException");
 
   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
@@ -1117,12 +1131,12 @@ bailout:
 /* 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)
+   jobjectArray dstobjs, jobjectArray tobjs)
 {
   tjhandle handle = 0;
   unsigned char *jpegBuf = NULL, **dstBufs = NULL;
   jsize n = 0;
-  unsigned long *dstSizes = NULL;
+  size_t *dstSizes = NULL;
   tjtransform *t = NULL;
   jbyteArray *jdstBufs = NULL;
   int i, jpegWidth = 0, jpegHeight = 0, jpegSubsamp;
@@ -1134,12 +1148,12 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
 
   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);
+  if ((jpegWidth = tj3Get(handle, TJPARAM_JPEGWIDTH)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+  if ((jpegHeight = tj3Get(handle, TJPARAM_JPEGHEIGHT)) == -1)
+    THROW_ARG("JPEG header has not yet been read");
+  if ((jpegSubsamp = tj3Get(handle, TJPARAM_SUBSAMP)) == TJSAMP_UNKNOWN)
+    THROW_ARG("TJPARAM_SUBSAMP must be specified");
 
   n = (*env)->GetArrayLength(env, dstobjs);
   if (n != (*env)->GetArrayLength(env, tobjs))
@@ -1150,7 +1164,7 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
     THROW_MEM();
   if ((jdstBufs = (jbyteArray *)malloc(sizeof(jbyteArray) * n)) == NULL)
     THROW_MEM();
-  if ((dstSizes = (unsigned long *)malloc(sizeof(unsigned long) * n)) == NULL)
+  if ((dstSizes = (size_t *)malloc(sizeof(size_t) * n)) == NULL)
     THROW_MEM();
   if ((t = (tjtransform *)malloc(sizeof(tjtransform) * n)) == NULL)
     THROW_MEM();
@@ -1193,14 +1207,21 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
     }
   }
 
+  if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
+    THROW_TJ();
+
   for (i = 0; i < n; i++) {
     int w = jpegWidth, h = jpegHeight;
 
+    if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
+        t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
+      w = jpegHeight;  h = jpegWidth;
+    }
     if (t[i].r.w != 0) w = t[i].r.w;
     if (t[i].r.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))
+    if ((size_t)(*env)->GetArrayLength(env, jdstBufs[i]) <
+        tj3JPEGBufSize(w, h, jpegSubsamp))
       THROW_ARG("Destination buffer is not large enough");
   }
   BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
@@ -1208,8 +1229,7 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
     BAILIF0NOEC(dstBufs[i] =
                 (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
 
-  if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
-                  flags | TJFLAG_NOREALLOC) == -1) {
+  if (tj3Transform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t) == -1) {
     for (i = 0; i < n; i++)
       SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
     SAFE_RELEASE(jsrcBuf, jpegBuf);
@@ -1246,3 +1266,135 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
 {
   Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj);
 }
+
+/* Private image I/O routines (used only by TJBench) */
+JNIEXPORT jobject JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_loadImage
+  (JNIEnv *env, jobject obj, jint precision, jstring jfilename,
+   jintArray jwidth, jint align, jintArray jheight, jintArray jpixelFormat)
+{
+  tjhandle handle = NULL;
+  void *dstBuf = NULL, *jdstPtr;
+  int width, *warr, height, *harr, pixelFormat, *pfarr, n;
+  const char *filename = NULL;
+  jboolean isCopy;
+  jobject jdstBuf = NULL;
+
+  GET_HANDLE();
+
+  if ((precision != 8 && precision != 12 && precision != 16) ||
+      jfilename == NULL || jwidth == NULL ||
+      (*env)->GetArrayLength(env, jwidth) < 1 || jheight == NULL ||
+      (*env)->GetArrayLength(env, jheight) < 1 || jpixelFormat == NULL ||
+      (*env)->GetArrayLength(env, jpixelFormat) < 1)
+    THROW_ARG("Invalid argument in loadImage()");
+
+  BAILIF0NOEC(warr = (*env)->GetPrimitiveArrayCritical(env, jwidth, 0));
+  width = warr[0];
+  (*env)->ReleasePrimitiveArrayCritical(env, jwidth, warr, 0);
+  BAILIF0NOEC(harr = (*env)->GetPrimitiveArrayCritical(env, jheight, 0));
+  height = harr[0];
+  (*env)->ReleasePrimitiveArrayCritical(env, jheight, harr, 0);
+  BAILIF0NOEC(pfarr = (*env)->GetPrimitiveArrayCritical(env, jpixelFormat, 0));
+  pixelFormat = pfarr[0];
+  (*env)->ReleasePrimitiveArrayCritical(env, jpixelFormat, pfarr, 0);
+  BAILIF0(filename = (*env)->GetStringUTFChars(env, jfilename, &isCopy));
+
+  if (precision == 8) {
+    if ((dstBuf = tj3LoadImage8(handle, filename, &width, align, &height,
+                                &pixelFormat)) == NULL)
+      THROW_TJ();
+  } else if (precision == 12) {
+    if ((dstBuf = tj3LoadImage12(handle, filename, &width, align, &height,
+                                 &pixelFormat)) == NULL)
+      THROW_TJ();
+  } else {
+    if ((dstBuf = tj3LoadImage16(handle, filename, &width, align, &height,
+                                 &pixelFormat)) == NULL)
+      THROW_TJ();
+  }
+
+  (*env)->ReleaseStringUTFChars(env, jfilename, filename);
+  filename = NULL;
+
+  if ((unsigned long long)width * (unsigned long long)height *
+      (unsigned long long)tjPixelSize[pixelFormat] >
+      (unsigned long long)((unsigned int)-1))
+    THROW_ARG("Image is too large");
+
+  BAILIF0NOEC(warr = (*env)->GetPrimitiveArrayCritical(env, jwidth, 0));
+  warr[0] = width;
+  (*env)->ReleasePrimitiveArrayCritical(env, jwidth, warr, 0);
+  BAILIF0NOEC(harr = (*env)->GetPrimitiveArrayCritical(env, jheight, 0));
+  harr[0] = height;
+  (*env)->ReleasePrimitiveArrayCritical(env, jheight, harr, 0);
+  BAILIF0NOEC(pfarr = (*env)->GetPrimitiveArrayCritical(env, jpixelFormat, 0));
+  pfarr[0] = pixelFormat;
+  (*env)->ReleasePrimitiveArrayCritical(env, jpixelFormat, pfarr, 0);
+
+  n = width * height * tjPixelSize[pixelFormat];
+  if (precision == 8)
+    jdstBuf = (*env)->NewByteArray(env, n);
+  else
+    jdstBuf = (*env)->NewShortArray(env, n);
+  BAILIF0NOEC(jdstPtr = (*env)->GetPrimitiveArrayCritical(env, jdstBuf, 0));
+  memcpy(jdstPtr, dstBuf, n * (precision > 8 ? 2 : 1));
+  (*env)->ReleasePrimitiveArrayCritical(env, jdstBuf, jdstPtr, 0);
+
+bailout:
+  if (filename) (*env)->ReleaseStringUTFChars(env, jfilename, filename);
+  tj3Free(dstBuf);
+  return jdstBuf;
+}
+
+
+JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_saveImage
+  (JNIEnv *env, jobject obj, jint precision, jstring jfilename,
+   jobject jsrcBuf, jint width, jint pitch, jint height, jint pixelFormat)
+{
+  tjhandle handle = NULL;
+  void *srcBuf = NULL, *jsrcPtr;
+  const char *filename = NULL;
+  int n;
+  jboolean isCopy;
+
+  GET_HANDLE();
+
+  if ((precision != 8 && precision != 12 && precision != 16) ||
+      jfilename == NULL || jsrcBuf == NULL || width < 1 || height < 1 ||
+      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
+    THROW_ARG("Invalid argument in saveImage()");
+
+  if ((unsigned long long)width * (unsigned long long)height *
+      (unsigned long long)tjPixelSize[pixelFormat] >
+      (unsigned long long)((unsigned int)-1))
+    THROW_ARG("Image is too large");
+  n = width * height * tjPixelSize[pixelFormat];
+  if ((*env)->GetArrayLength(env, jsrcBuf) < n)
+    THROW_ARG("Source buffer is not large enough");
+
+  if ((srcBuf = malloc(n * (precision > 8 ? 2 : 1))) == NULL)
+    THROW_MEM();
+
+  BAILIF0NOEC(jsrcPtr = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
+  memcpy(srcBuf, jsrcPtr, n * (precision > 8 ? 2 : 1));
+  (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jsrcPtr, 0);
+  BAILIF0(filename = (*env)->GetStringUTFChars(env, jfilename, &isCopy));
+
+  if (precision == 8) {
+    if (tj3SaveImage8(handle, filename, srcBuf, width, pitch, height,
+                      pixelFormat) == -1)
+      THROW_TJ();
+  } else if (precision == 12) {
+    if (tj3SaveImage12(handle, filename, srcBuf, width, pitch, height,
+                       pixelFormat) == -1)
+      THROW_TJ();
+  } else {
+    if (tj3SaveImage16(handle, filename, srcBuf, width, pitch, height,
+                       pixelFormat) == -1)
+      THROW_TJ();
+  }
+
+bailout:
+  if (filename) (*env)->ReleaseStringUTFChars(env, jfilename, filename);
+  free(srcBuf);
+}
index 5477fed..6aab871 100644 (file)
@@ -1,14 +1,14 @@
 TURBOJPEG_1.0
 {
   global:
-    tjInitCompress;
-    tjCompress;
     TJBUFSIZE;
-    tjInitDecompress;
-    tjDecompressHeader;
+    tjCompress;
     tjDecompress;
+    tjDecompressHeader;
     tjDestroy;
     tjGetErrorStr;
+    tjInitCompress;
+    tjInitDecompress;
   local:
     *;
 };
@@ -63,3 +63,46 @@ TURBOJPEG_2.0
     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;
index 4432791..31be750 100644 (file)
@@ -1,14 +1,14 @@
 TURBOJPEG_1.0
 {
   global:
-    tjInitCompress;
-    tjCompress;
     TJBUFSIZE;
-    tjInitDecompress;
-    tjDecompressHeader;
+    tjCompress;
     tjDecompress;
+    tjDecompressHeader;
     tjDestroy;
     tjGetErrorStr;
+    tjInitCompress;
+    tjInitDecompress;
   local:
     *;
 };
@@ -36,33 +36,16 @@ TURBOJPEG_1.2
     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:
@@ -80,16 +63,10 @@ TURBOJPEG_1.4
     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_1.2;
 
 TURBOJPEG_2.0
 {
@@ -99,3 +76,67 @@ TURBOJPEG_2.0
     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_loadImage;
+    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_saveImage;
+    Java_org_libjpegturbo_turbojpeg_TJDecompressor_set;
+    Java_org_libjpegturbo_turbojpeg_TJDecompressor_setCroppingRegion;
+} TURBOJPEG_2.0;
diff --git a/turbojpeg-mp.c b/turbojpeg-mp.c
new file mode 100644 (file)
index 0000000..5699869
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C)2009-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.
+ */
+
+/* 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+ */
+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;
+
+  setCompDefaults(this, pixelFormat);
+  if (this->noRealloc) {
+    alloc = FALSE;
+    *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
+  }
+  jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
+
+  jpeg_start_compress(cinfo, TRUE);
+  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) {
+    if (alloc) (*cinfo->dest->term_destination) (cinfo);
+    jpeg_abort_compress(cinfo);
+  }
+  free(row_pointer);
+  if (this->jerr.warning) retval = -1;
+  return retval;
+}
+
+
+/******************************* Decompressor ********************************/
+
+/* TurboJPEG 3+ */
+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;
+
+  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_START) {
+    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+    jpeg_read_header(dinfo, TRUE);
+  }
+  setDecompParameters(this);
+  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+ */
+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 ((src = _jinit_read_ppm(cinfo)) == NULL)
+      THROW("Could not initialize PPM loader");
+    invert = this->bottomUp;
+  } else
+    THROW("Unsupported file type");
+
+  src->input_file = file;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  /* Refuse to load images larger than 1 Megapixel when fuzzing. */
+  src->max_pixels = this->maxPixels;
+#endif
+  (*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 ((unsigned long long)pitch * (unsigned long long)(*height) >
+      (unsigned long long)((size_t)-1) ||
+      (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+ */
+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 ((dst = _jinit_write_ppm(dinfo)) == NULL)
+      THROW("Could not initialize PPM writer");
+    invert = this->bottomUp;
+  }
+
+  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
index a1544f2..b75d414 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2009-2022 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2009-2023 D. R. Commander.  All Rights Reserved.
  * Copyright (C)2021 Alex Richardson.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
    libjpeg-turbo */
 
 #include <ctype.h>
+#include <limits.h>
 #include <jinclude.h>
 #define JPEG_INTERNALS
 #include <jpeglib.h>
 #include "./turbojpeg.h"
 #include "./tjutil.h"
 #include "transupp.h"
-#include "./jpegcomp.h"
+#include "./jpegapicomp.h"
 #include "./cdjpeg.h"
-#include "jconfigint.h"
 
-extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
+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 *,
-                            unsigned long);
+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.txt) */
+/* Error handling (based on example in example.c) */
 
 static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error";
 
@@ -98,7 +97,7 @@ static void my_emit_message(j_common_ptr cinfo, int msg_level)
 }
 
 
-/* Global structures, macros, etc. */
+/********************** Global structures, macros, etc. **********************/
 
 enum { COMPRESS = 1, DECOMPRESS = 2 };
 
@@ -106,11 +105,42 @@ typedef struct _tjinstance {
   struct jpeg_compress_struct cinfo;
   struct jpeg_decompress_struct dinfo;
   struct my_error_mgr jerr;
-  int init, headerRead;
+  int init;
   char errStr[JMSG_LENGTH_MAX];
   boolean isInstanceError;
+  /* Parameters */
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  int maxPixels;
+#endif
+  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;
 } tjinstance;
 
+static tjhandle _tjInitCompress(tjinstance *this);
+static tjhandle _tjInitDecompress(tjinstance *this);
+
 struct my_progress_mgr {
   struct jpeg_progress_mgr pub;
   tjinstance *this;
@@ -125,11 +155,13 @@ static void my_progress_monitor(j_common_ptr dinfo)
   if (dinfo->is_decompressor) {
     int scan_no = ((j_decompress_ptr)dinfo)->input_scan_number;
 
-    if (scan_no > 500) {
+    if (scan_no > myprog->this->scanLimit) {
       SNPRINTF(myprog->this->errStr, JMSG_LENGTH_MAX,
-               "Progressive JPEG image has more than 500 scans");
+               "Progressive JPEG image has more than %d scans",
+               myprog->this->scanLimit);
       SNPRINTF(errStr, JMSG_LENGTH_MAX,
-               "Progressive JPEG image has more than 500 scans");
+               "Progressive JPEG image has more than %d scans",
+               myprog->this->scanLimit);
       myprog->this->isInstanceError = TRUE;
       myerr->warning = FALSE;
       longjmp(myerr->setjmp_buffer, 1);
@@ -137,8 +169,6 @@ static void my_progress_monitor(j_common_ptr dinfo)
   }
 }
 
-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
@@ -190,32 +220,43 @@ static int cs2pf[JPEG_NUMCS] = {
   TJPF_UNKNOWN
 };
 
-#define THROWG(m) { \
-  SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s", m); \
-  retval = -1;  goto bailout; \
+#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(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerrorBuf); \
+  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(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \
+  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 THROW(m) { \
-  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s", m); \
-  this->isInstanceError = TRUE;  THROWG(m) \
+  SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, m); \
+  this->isInstanceError = TRUE;  THROWG(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; \
 }
-
-#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; \
@@ -223,7 +264,7 @@ static int cs2pf[JPEG_NUMCS] = {
   j_decompress_ptr dinfo = NULL; \
   \
   if (!this) { \
-    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
+    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
     return -1; \
   } \
   cinfo = &this->cinfo;  dinfo = &this->dinfo; \
@@ -235,7 +276,7 @@ static int cs2pf[JPEG_NUMCS] = {
   j_compress_ptr cinfo = NULL; \
   \
   if (!this) { \
-    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
+    SNPRINTF(errStr, JMSG_LENGTH_MAX, "%s(): Invalid handle", FUNCTION_NAME); \
     return -1; \
   } \
   cinfo = &this->cinfo; \
@@ -247,13 +288,23 @@ static int cs2pf[JPEG_NUMCS] = {
   j_decompress_ptr dinfo = NULL; \
   \
   if (!this) { \
-    SNPRINTF(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \
+    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;
@@ -273,80 +324,74 @@ static int getPixelFormat(int pixelSize, int flags)
   return -1;
 }
 
-static void setCompDefaults(struct jpeg_compress_struct *cinfo,
-                            int pixelFormat, int subsamp, int jpegQual,
-                            int flags)
+static void setCompDefaults(tjinstance *this, int pixelFormat)
 {
-#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) {
+  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;
+
+  if (this->lossless) {
+#ifdef C_LOSSLESS_SUPPORTED
+    jpeg_enable_lossless(&this->cinfo, this->losslessPSV, this->losslessPt);
 #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;
+    if (pixelFormat == TJPF_GRAY)
+      this->subsamp = TJSAMP_GRAY;
+    else if (this->subsamp != TJSAMP_GRAY)
+      this->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 (this->subsamp == TJSAMP_GRAY)
+      jpeg_set_colorspace(&this->cinfo, JCS_GRAYSCALE);
+    else if (pixelFormat == TJPF_CMYK)
+      jpeg_set_colorspace(&this->cinfo, JCS_YCCK);
     else
-      cinfo->dct_method = JDCT_FASTEST;
+      jpeg_set_colorspace(&this->cinfo, JCS_YCbCr);
   }
-  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);
 
-  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);
+  this->cinfo.optimize_coding = this->optimize;
+#ifdef C_PROGRESSIVE_SUPPORTED
+  if (this->progressive) jpeg_simple_progression(&this->cinfo);
 #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;
+  this->cinfo.arith_code = this->arithmetic;
+
+  this->cinfo.comp_info[0].h_samp_factor = tjMCUWidth[this->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[this->subsamp] / 8;
+  this->cinfo.comp_info[0].v_samp_factor = tjMCUHeight[this->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[this->subsamp] / 8;
 }
 
 
 static int getSubsamp(j_decompress_ptr dinfo)
 {
-  int retval = -1, i, k;
+  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
@@ -355,11 +400,13 @@ static int getSubsamp(j_decompress_ptr dinfo)
   if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
     return TJSAMP_GRAY;
 
-  for (i = 0; i < NUMSUBOPT; i++) {
-    if (dinfo->num_components == pixelsize[i] ||
+  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) &&
-         pixelsize[i] == 3 && dinfo->num_components == 4)) {
+         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;
@@ -405,7 +452,7 @@ static int getSubsamp(j_decompress_ptr dinfo)
          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) {
+          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 ==
@@ -424,9 +471,309 @@ static int getSubsamp(j_decompress_ptr dinfo)
 }
 
 
-/* General API functions */
+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;
+}
 
-DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
+
+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+ */
+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;
+
+  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;
+}
+
+
+#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+ */
+DLLEXPORT int tj3Set(tjhandle handle, int param, int value)
+{
+  static const char FUNCTION_NAME[] = "tj3Set";
+  int retval = 0;
+
+  GET_TJINSTANCE(handle, -1);
+
+  switch (param) {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  case TJPARAM_MAXPIXELS:
+    SET_PARAM(maxPixels, 0, -1);
+    break;
+#endif
+  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:
+    if (!(this->init & DECOMPRESS))
+      THROW("TJPARAM_PRECISION is not applicable to compression instances.");
+    THROW("TJPARAM_PRECISION is read-only in decompression instances.");
+    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, this->precision - 1);
+    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;
+  default:
+    THROW("Invalid parameter");
+  }
+
+bailout:
+  return retval;
+}
+
+
+/* TurboJPEG 3+ */
+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;
+  }
+
+  return -1;
+}
+
+
+/* TurboJPEG 3+ */
+DLLEXPORT char *tj3GetErrorStr(tjhandle handle)
 {
   tjinstance *this = (tjinstance *)handle;
 
@@ -437,14 +784,21 @@ DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
     return errStr;
 }
 
+/* TurboJPEG 2.0+ */
+DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
+{
+  return tj3GetErrorStr(handle);
+}
 
+/* TurboJPEG 1.0+ */
 DLLEXPORT char *tjGetErrorStr(void)
 {
   return errStr;
 }
 
 
-DLLEXPORT int tjGetErrorCode(tjhandle handle)
+/* TurboJPEG 3+ */
+DLLEXPORT int tj3GetErrorCode(tjhandle handle)
 {
   tjinstance *this = (tjinstance *)handle;
 
@@ -452,16 +806,46 @@ DLLEXPORT int tjGetErrorCode(tjhandle handle)
   else return TJERR_FATAL;
 }
 
+/* TurboJPEG 2.0+ */
+DLLEXPORT int tjGetErrorCode(tjhandle handle)
+{
+  return tj3GetErrorCode(handle);
+}
+
 
-DLLEXPORT int tjDestroy(tjhandle handle)
+/* TurboJPEG 3+ */
+DLLEXPORT void tj3Destroy(tjhandle handle)
 {
-  GET_INSTANCE(handle);
+  tjinstance *this = (tjinstance *)handle;
+  j_compress_ptr cinfo = NULL;
+  j_decompress_ptr dinfo = NULL;
+
+  if (!this) return;
 
-  if (setjmp(this->jerr.setjmp_buffer)) return -1;
+  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);
-  return 0;
+}
+
+/* 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;
 }
 
 
@@ -470,27 +854,41 @@ DLLEXPORT int tjDestroy(tjhandle handle)
    with turbojpeg.dll for compatibility reasons.  However, these functions
    can potentially be used for other purposes by different implementations. */
 
-DLLEXPORT void tjFree(unsigned char *buf)
+/* TurboJPEG 3+ */
+DLLEXPORT void tj3Free(void *buf)
 {
   free(buf);
 }
 
+/* TurboJPEG 1.2+ */
+DLLEXPORT void tjFree(unsigned char *buf)
+{
+  tj3Free(buf);
+}
+
+
+/* TurboJPEG 3+ */
+DLLEXPORT void *tj3Alloc(size_t bytes)
+{
+  return malloc(bytes);
+}
 
+/* TurboJPEG 1.2+ */
 DLLEXPORT unsigned char *tjAlloc(int bytes)
 {
-  return (unsigned char *)malloc(bytes);
+  return (unsigned char *)tj3Alloc((size_t)bytes);
 }
 
 
-/* Compressor  */
+/******************************** Compressor *********************************/
 
 static tjhandle _tjInitCompress(tjinstance *this)
 {
   static unsigned char buffer[1];
   unsigned char *buf = buffer;
-  unsigned long size = 1;
+  size_t size = 1;
 
-  /* This is also straight out of example.txt */
+  /* 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;
@@ -514,28 +912,26 @@ static tjhandle _tjInitCompress(tjinstance *this)
   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);
+  return tj3Init(TJINIT_COMPRESS);
 }
 
 
-DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
+/* TurboJPEG 3+ */
+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 < 0 || jpegSubsamp >= NUMSUBOPT)
-    THROWG("tjBufSize(): Invalid argument");
+  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
@@ -545,209 +941,246 @@ DLLEXPORT unsigned long tjBufSize(int width, int height, int 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");
+    THROWG("Image is too large", 0);
 
 bailout:
-  return (unsigned long)retval;
+  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("TJBUFSIZE(): Invalid argument");
+    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 (retval > (unsigned long long)((unsigned long)-1))
-    THROWG("TJBUFSIZE(): Image is too large");
+    THROWG("Image is too large", (unsigned long)-1);
 
 bailout:
   return (unsigned long)retval;
 }
 
 
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
-                                      int subsamp)
+/* TurboJPEG 3+ */
+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 (subsamp < 0 || subsamp >= NUMSUBOPT)
-    THROWG("tjBufSizeYUV2(): Invalid argument");
+  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 = tjPlaneWidth(i, width, subsamp);
-    int stride = PAD(pw, pad);
-    int ph = tjPlaneHeight(i, height, subsamp);
+    int pw = tj3YUVPlaneWidth(i, width, subsamp);
+    int stride = PAD(pw, align);
+    int ph = tj3YUVPlaneHeight(i, height, subsamp);
 
-    if (pw < 0 || ph < 0) return -1;
+    if (pw == 0 || ph == 0) return 0;
     else retval += (unsigned long long)stride * ph;
   }
   if (retval > (unsigned long long)((unsigned long)-1))
-    THROWG("tjBufSizeYUV2(): Image is too large");
+    THROWG("Image is too large", 0);
 
 bailout:
-  return (unsigned long)retval;
+  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);
 }
 
 
-DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
+/* TurboJPEG 3+ */
+DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp)
 {
-  int pw, nc, retval = 0;
+  static const char FUNCTION_NAME[] = "tj3YUVPlaneWidth";
+  unsigned long long pw, retval = 0;
+  int nc;
 
   if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
-    THROWG("tjPlaneWidth(): Invalid argument");
+    THROWG("Invalid argument", 0);
   nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
   if (componentID < 0 || componentID >= nc)
-    THROWG("tjPlaneWidth(): Invalid argument");
+    THROWG("Invalid argument", 0);
 
-  pw = PAD(width, tjMCUWidth[subsamp] / 8);
+  pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
   if (componentID == 0)
     retval = pw;
   else
     retval = pw * 8 / tjMCUWidth[subsamp];
 
+  if (retval > (unsigned long long)INT_MAX)
+    THROWG("Width is too large", 0);
+
 bailout:
-  return retval;
+  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;
 }
 
 
-DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
+/* TurboJPEG 3+ */
+DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp)
 {
-  int ph, nc, retval = 0;
+  static const char FUNCTION_NAME[] = "tj3YUVPlaneHeight";
+  unsigned long long ph, retval = 0;
+  int nc;
 
   if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
-    THROWG("tjPlaneHeight(): Invalid argument");
+    THROWG("Invalid argument", 0);
   nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
   if (componentID < 0 || componentID >= nc)
-    THROWG("tjPlaneHeight(): Invalid argument");
+    THROWG("Invalid argument", 0);
 
-  ph = PAD(height, tjMCUHeight[subsamp] / 8);
+  ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
   if (componentID == 0)
     retval = ph;
   else
     retval = ph * 8 / tjMCUHeight[subsamp];
 
+  if (retval > (unsigned long long)INT_MAX)
+    THROWG("Height is too large", 0);
+
 bailout:
-  return retval;
+  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;
 }
 
 
-DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
-                                       int height, int subsamp)
+/* TurboJPEG 3+ */
+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 >= NUMSUBOPT)
-    THROWG("tjPlaneSizeYUV(): Invalid argument");
+  if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
+    THROWG("Invalid argument", 0);
 
-  pw = tjPlaneWidth(componentID, width, subsamp);
-  ph = tjPlaneHeight(componentID, height, subsamp);
-  if (pw < 0 || ph < 0) return -1;
+  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 (retval > (unsigned long long)((unsigned long)-1))
-    THROWG("tjPlaneSizeYUV(): Image is too large");
+    THROWG("Image is too large", 0);
 
 bailout:
-  return (unsigned long)retval;
+  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;
 }
 
 
+/* 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)
 {
-  int i, retval = 0;
-  boolean alloc = TRUE;
-  JSAMPROW *row_pointer = NULL;
+  static const char FUNCTION_NAME[] = "tjCompress2";
+  int retval = 0;
+  size_t size;
 
-  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");
+  GET_TJINSTANCE(handle, -1);
 
-  if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
-      pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
-      jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT ||
+  if (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
+    THROW("Invalid argument");
 
-  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);
+  this->quality = jpegQual;
+  this->subsamp = jpegSubsamp;
+  processFlags(handle, flags, COMPRESS);
 
-  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);
+  size = (size_t)(*jpegSize);
+  retval = tj3Compress8(handle, srcBuf, width, pitch, height, pixelFormat,
+                        jpegBuf, &size);
+  *jpegSize = (unsigned long)size;
 
 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;
+  unsigned long size = jpegSize ? *jpegSize : 0;
 
   if (flags & TJ_YUV) {
     size = tjBufSizeYUV(width, height, jpegSubsamp);
@@ -764,11 +1197,13 @@ DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
 }
 
 
-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)
+/* TurboJPEG 3+ */
+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];
@@ -777,8 +1212,7 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
   JSAMPLE *ptr;
   jpeg_component_info *compptr;
 
-  GET_CINSTANCE(handle);
-  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
+  GET_CINSTANCE(handle)
 
   for (i = 0; i < MAX_COMPONENTS; i++) {
     tmpbuf[i] = NULL;  _tmpbuf[i] = NULL;
@@ -786,17 +1220,19 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
   }
 
   if ((this->init & COMPRESS) == 0)
-    THROW("tjEncodeYUVPlanes(): Instance has not been initialized for compression");
+    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] || subsamp < 0 || subsamp >= NUMSUBOPT)
-    THROW("tjEncodeYUVPlanes(): Invalid argument");
-  if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
-    THROW("tjEncodeYUVPlanes(): Invalid argument");
+      !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("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
+    THROW("Cannot generate YUV images from packed-pixel CMYK images");
 
   if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
 
@@ -807,21 +1243,16 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
 
   cinfo->image_width = width;
   cinfo->image_height = height;
+  cinfo->data_precision = 8;
 
-#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);
+  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("tjEncodeYUVPlanes(): libjpeg API is in the wrong state");
+    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);
@@ -832,9 +1263,9 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
   ph0 = PAD(height, cinfo->max_v_samp_factor);
 
   if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
-    THROW("tjEncodeYUVPlanes(): Memory allocation failure");
+    THROW("Memory allocation failure");
   for (i = 0; i < height; i++) {
-    if (flags & TJFLAG_BOTTOMUP)
+    if (this->bottomUp)
       row_pointer[i] = (JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch];
     else
       row_pointer[i] = (JSAMPROW)&srcBuf[i * (size_t)pitch];
@@ -849,11 +1280,11 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
           compptr->h_samp_factor, 32) *
       cinfo->max_v_samp_factor + 32);
     if (!_tmpbuf[i])
-      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     tmpbuf[i] =
       (JSAMPROW *)malloc(sizeof(JSAMPROW) * cinfo->max_v_samp_factor);
     if (!tmpbuf[i])
-      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
+      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);
@@ -866,10 +1297,10 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
       (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
                         compptr->v_samp_factor + 32);
     if (!_tmpbuf2[i])
-      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     tmpbuf2[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
     if (!tmpbuf2[i])
-      THROW("tjEncodeYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     for (row = 0; row < compptr->v_samp_factor; row++) {
       unsigned char *_tmpbuf2_aligned =
         (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32);
@@ -881,7 +1312,7 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
     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");
+      THROW("Memory allocation failure");
     ptr = dstPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       outbuf[i][row] = ptr;
@@ -918,57 +1349,109 @@ bailout:
     free(outbuf[i]);
   }
   if (this->jerr.warning) retval = -1;
-  this->jerr.stopOnWarning = FALSE;
   return retval;
 }
 
-DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
-                           int width, int pitch, int height, int pixelFormat,
-                           unsigned char *dstBuf, int pad, int subsamp,
-                           int flags)
+/* 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+ */
+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;
-  tjinstance *this = (tjinstance *)handle;
 
-  if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
-  this->isInstanceError = FALSE;
+  GET_TJINSTANCE(handle, -1);
+
+  if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
+      !IS_POW2(align))
+    THROW("Invalid argument");
 
-  if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 ||
-      !IS_POW2(pad) || subsamp < 0 || subsamp >= NUMSUBOPT)
-    THROW("tjEncodeYUV3(): Invalid argument");
+  if (this->subsamp == TJSAMP_UNKNOWN)
+    THROW("TJPARAM_SUBSAMP must be specified");
 
-  pw0 = tjPlaneWidth(0, width, subsamp);
-  ph0 = tjPlaneHeight(0, height, subsamp);
+  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
   dstPlanes[0] = dstBuf;
-  strides[0] = PAD(pw0, pad);
-  if (subsamp == TJSAMP_GRAY) {
+  strides[0] = PAD(pw0, align);
+  if (this->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);
+    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
 
-    strides[1] = strides[2] = PAD(pw1, pad);
+    strides[1] = strides[2] = PAD(pw1, align);
     dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
     dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
   }
 
-  return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat,
-                           dstPlanes, strides, subsamp, flags);
+  return tj3EncodeYUVPlanes8(handle, srcBuf, width, pitch, height, pixelFormat,
+                             dstPlanes, strides);
 
 bailout:
   return retval;
 }
 
-DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
-                           int pitch, int height, int pixelFormat,
-                           unsigned char *dstBuf, int subsamp, int flags)
+/* 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)
 {
-  return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat,
-                      dstBuf, 4, subsamp, 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)
@@ -979,14 +1462,14 @@ DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
 }
 
 
-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)
+/* TurboJPEG 3+ */
+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],
@@ -995,21 +1478,24 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
   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");
+    THROW("Instance has not been initialized for compression");
 
   if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
-      subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL ||
-      jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
-    THROW("tjCompressFromYUVPlanes(): Invalid argument");
-  if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
-    THROW("tjCompressFromYUVPlanes(): Invalid argument");
+      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. */
@@ -1018,18 +1504,13 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
 
   cinfo->image_width = width;
   cinfo->image_height = height;
+  cinfo->data_precision = 8;
 
-#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);
+  if (this->noRealloc) {
+    alloc = FALSE;  *jpegSize = tj3JPEGBufSize(width, height, this->subsamp);
   }
   jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
-  setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags);
+  setCompDefaults(this, TJPF_RGB);
   cinfo->raw_data_in = TRUE;
 
   jpeg_start_compress(cinfo, TRUE);
@@ -1047,7 +1528,7 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
     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");
+      THROW("Memory allocation failure");
     ptr = (JSAMPLE *)srcPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       inbuf[i][row] = ptr;
@@ -1056,11 +1537,11 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
   }
   if (usetmpbuf) {
     if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
-      THROW("tjCompressFromYUVPlanes(): Memory allocation failure");
+      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("tjCompressFromYUVPlanes(): Memory allocation failure");
+        THROW("Memory allocation failure");
       for (row = 0; row < th[i]; row++) {
         tmpbuf[i][row] = ptr;
         ptr += iw[i];
@@ -1113,58 +1594,121 @@ bailout:
   }
   free(_tmpbuf);
   if (this->jerr.warning) retval = -1;
-  this->jerr.stopOnWarning = FALSE;
   return retval;
 }
 
-DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
-                                int width, int pad, int height, int subsamp,
-                                unsigned char **jpegBuf,
-                                unsigned long *jpegSize, int jpegQual,
-                                int 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)
+{
+  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);
+  retval = tj3CompressFromYUVPlanes8(handle, srcPlanes, width, strides, height,
+                                     jpegBuf, &size);
+  *jpegSize = (unsigned long)size;
+
+bailout:
+  return retval;
+}
+
+
+/* TurboJPEG 3+ */
+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;
-  tjinstance *this = (tjinstance *)handle;
 
-  if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
-  this->isInstanceError = FALSE;
+  GET_TJINSTANCE(handle, -1);
 
-  if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 ||
-      subsamp >= NUMSUBOPT)
-    THROW("tjCompressFromYUV(): Invalid argument");
+  if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
+      height <= 0)
+    THROW("Invalid argument");
 
-  pw0 = tjPlaneWidth(0, width, subsamp);
-  ph0 = tjPlaneHeight(0, height, subsamp);
+  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, pad);
-  if (subsamp == TJSAMP_GRAY) {
+  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, subsamp);
-    int ph1 = tjPlaneHeight(1, height, subsamp);
+    int pw1 = tjPlaneWidth(1, width, this->subsamp);
+    int ph1 = tjPlaneHeight(1, height, this->subsamp);
 
-    strides[1] = strides[2] = PAD(pw1, pad);
+    strides[1] = strides[2] = PAD(pw1, align);
     srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
     srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
   }
 
-  return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height,
-                                 subsamp, jpegBuf, jpegSize, jpegQual, flags);
+  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);
+  retval = tj3CompressFromYUV8(handle, srcBuf, width, align, height, jpegBuf,
+                               &size);
+  *jpegSize = (unsigned long)size;
 
 bailout:
   return retval;
 }
 
 
-/* Decompressor */
+/******************************* Decompressor ********************************/
 
 static tjhandle _tjInitDecompress(tjinstance *this)
 {
   static unsigned char buffer[1];
 
-  /* This is also straight out of example.txt */
+  /* 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;
@@ -1188,36 +1732,27 @@ static tjhandle _tjInitDecompress(tjinstance *this)
   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);
+  return tj3Init(TJINIT_DECOMPRESS);
 }
 
 
-DLLEXPORT int tjDecompressHeader3(tjhandle handle,
+/* TurboJPEG 3+ */
+DLLEXPORT int tj3DecompressHeader(tjhandle handle,
                                   const unsigned char *jpegBuf,
-                                  unsigned long jpegSize, int *width,
-                                  int *height, int *jpegSubsamp,
-                                  int *jpegColorspace)
+                                  size_t jpegSize)
 {
+  static const char FUNCTION_NAME[] = "tj3DecompressHeader";
   int retval = 0;
 
   GET_DINSTANCE(handle);
   if ((this->init & DECOMPRESS) == 0)
-    THROW("tjDecompressHeader3(): Instance has not been initialized for decompression");
+    THROW("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 (jpegBuf == NULL || jpegSize <= 0)
+    THROW("Invalid argument");
 
   if (setjmp(this->jerr.setjmp_buffer)) {
     /* If we get here, the JPEG code has signaled an error. */
@@ -1233,32 +1768,50 @@ DLLEXPORT int tjDecompressHeader3(tjhandle handle,
   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;
-  }
+  setDecompParameters(this);
 
   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");
+  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)
@@ -1269,6 +1822,7 @@ DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
                              jpegSubsamp, &jpegColorspace);
 }
 
+/* TurboJPEG 1.0+ */
 DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
                                  unsigned long jpegSize, int *width,
                                  int *height)
@@ -1280,50 +1834,121 @@ DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
 }
 
 
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
+/* TurboJPEG 3+ */
+DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors)
 {
-  if (numscalingfactors == NULL) {
-    SNPRINTF(errStr, JMSG_LENGTH_MAX,
-             "tjGetScalingFactors(): Invalid argument");
-    return NULL;
+  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+ */
+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+ */
+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;
   }
 
-  *numscalingfactors = NUMSF;
-  return (tjscalingfactor *)sf;
+  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 == 16 || 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 MCU 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)
 {
-  JSAMPROW *row_pointer = NULL;
+  static const char FUNCTION_NAME[] = "tjDecompress2";
   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
+    THROW("Instance has not been initialized for decompression");
 
-  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 (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. */
@@ -1332,10 +1957,6 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
 
   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;
@@ -1346,40 +1967,23 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
       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;
+    THROW("Could not scale down to desired image dimensions");
 
-  jpeg_start_decompress(dinfo);
-  if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
+  processFlags(handle, flags, DECOMPRESS);
 
-  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);
+  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);
-  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,
@@ -1393,44 +1997,42 @@ DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
 }
 
 
-static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
-                             int pixelFormat, int subsamp, int flags)
+static void setDecodeDefaults(tjinstance *this, int pixelFormat)
 {
   int i;
 
-  dinfo->scale_num = dinfo->scale_denom = 1;
+  this->dinfo.scale_num = this->dinfo.scale_denom = 1;
 
-  if (subsamp == TJSAMP_GRAY) {
-    dinfo->num_components = dinfo->comps_in_scan = 1;
-    dinfo->jpeg_color_space = JCS_GRAYSCALE;
+  if (this->subsamp == TJSAMP_GRAY) {
+    this->dinfo.num_components = this->dinfo.comps_in_scan = 1;
+    this->dinfo.jpeg_color_space = JCS_GRAYSCALE;
   } else {
-    dinfo->num_components = dinfo->comps_in_scan = 3;
-    dinfo->jpeg_color_space = JCS_YCbCr;
+    this->dinfo.num_components = this->dinfo.comps_in_scan = 3;
+    this->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));
+  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 < dinfo->num_components; i++) {
-    jpeg_component_info *compptr = &dinfo->comp_info[i];
+  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[subsamp] / 8 : 1;
-    compptr->v_samp_factor = (i == 0) ? tjMCUHeight[subsamp] / 8 : 1;
+    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;
-    dinfo->cur_comp_info[i] = compptr;
+    this->dinfo.cur_comp_info[i] = compptr;
   }
-  dinfo->data_precision = 8;
+  this->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);
+    if (this->dinfo.quant_tbl_ptrs[i] == NULL)
+      this->dinfo.quant_tbl_ptrs[i] =
+        jpeg_alloc_quant_table((j_common_ptr)&this->dinfo);
   }
-
-  return 0;
 }
 
 
@@ -1443,12 +2045,14 @@ static void my_reset_marker_reader(j_decompress_ptr dinfo)
 {
 }
 
-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)
+/* TurboJPEG 3+ */
+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];
@@ -1459,46 +2063,38 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
   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");
+    THROW("Instance has not been initialized for decompression");
 
-  if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT ||
-      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 (!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("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
+    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;
 
-#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;
-  if (setDecodeDefaults(dinfo, pixelFormat, subsamp, flags) == -1) {
-    retval = -1;  goto bailout;
-  }
+  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;
@@ -1508,7 +2104,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
   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;
+  this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
   dinfo->do_fancy_upsampling = FALSE;
   dinfo->Se = DCTSIZE2 - 1;
   jinit_master_decompress(dinfo);
@@ -1520,9 +2116,9 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
   if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat];
 
   if ((row_pointer = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph0)) == NULL)
-    THROW("tjDecodeYUVPlanes(): Memory allocation failure");
+    THROW("Memory allocation failure");
   for (i = 0; i < height; i++) {
-    if (flags & TJFLAG_BOTTOMUP)
+    if (this->bottomUp)
       row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch];
     else
       row_pointer[i] = &dstBuf[i * (size_t)pitch];
@@ -1536,10 +2132,10 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
       (JSAMPLE *)malloc(PAD(compptr->width_in_blocks * DCTSIZE, 32) *
                         compptr->v_samp_factor + 32);
     if (!_tmpbuf[i])
-      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     tmpbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * compptr->v_samp_factor);
     if (!tmpbuf[i])
-      THROW("tjDecodeYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     for (row = 0; row < compptr->v_samp_factor; row++) {
       unsigned char *_tmpbuf_aligned =
         (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32);
@@ -1551,7 +2147,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
     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");
+      THROW("Memory allocation failure");
     ptr = (JSAMPLE *)srcPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       inbuf[i][row] = ptr;
@@ -1587,57 +2183,110 @@ bailout:
     free(inbuf[i]);
   }
   if (this->jerr.warning) retval = -1;
-  this->jerr.stopOnWarning = FALSE;
   return retval;
 }
 
-DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
-                          int pad, int subsamp, unsigned char *dstBuf,
-                          int width, int pitch, int height, int pixelFormat,
-                          int flags)
+/* 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+ */
+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;
-  tjinstance *this = (tjinstance *)handle;
 
-  if (!this) THROWG("tjDecodeYUV(): Invalid handle");
-  this->isInstanceError = FALSE;
+  GET_TJINSTANCE(handle, -1);
+
+  if (srcBuf == NULL || align < 1 || !IS_POW2(align) || width <= 0 ||
+      height <= 0)
+    THROW("Invalid argument");
 
-  if (srcBuf == NULL || pad < 0 || !IS_POW2(pad) || subsamp < 0 ||
-      subsamp >= NUMSUBOPT || width <= 0 || height <= 0)
-    THROW("tjDecodeYUV(): Invalid argument");
+  if (this->subsamp == TJSAMP_UNKNOWN)
+    THROW("TJPARAM_SUBSAMP must be specified");
 
-  pw0 = tjPlaneWidth(0, width, subsamp);
-  ph0 = tjPlaneHeight(0, height, subsamp);
+  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
   srcPlanes[0] = srcBuf;
-  strides[0] = PAD(pw0, pad);
-  if (subsamp == TJSAMP_GRAY) {
+  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, subsamp);
-    int ph1 = tjPlaneHeight(1, height, subsamp);
+    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
 
-    strides[1] = strides[2] = PAD(pw1, pad);
+    strides[1] = strides[2] = PAD(pw1, align);
     srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
     srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
   }
 
-  return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width,
-                           pitch, height, pixelFormat, flags);
+  return tj3DecodeYUVPlanes8(handle, srcPlanes, strides, dstBuf, width, pitch,
+                             height, pixelFormat);
 
 bailout:
   return retval;
 }
 
-DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
-                                      const unsigned char *jpegBuf,
-                                      unsigned long jpegSize,
-                                      unsigned char **dstPlanes, int width,
-                                      int *strides, int height, int flags)
+/* 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;
+}
+
+
+/* TurboJPEG 3+ */
+DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
+                                        const unsigned char *jpegBuf,
+                                        size_t jpegSize,
+                                        unsigned char **dstPlanes,
+                                        int *strides)
 {
-  int i, sfi, row, retval = 0;
-  int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
+  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;
@@ -1646,26 +2295,18 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
   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");
+    THROW("Instance has not been initialized for decompression");
 
-  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0] ||
-      width < 0 || height < 0)
-    THROW("tjDecompressToYUVPlanes(): Invalid argument");
+  if (jpegBuf == NULL || jpegSize <= 0 || !dstPlanes || !dstPlanes[0])
+    THROW("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) {
+  if (this->scanLimit) {
     memset(&progress, 0, sizeof(struct my_progress_mgr));
     progress.pub.progress_monitor = my_progress_monitor;
     progress.this = this;
@@ -1678,39 +2319,25 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
     retval = -1;  goto bailout;
   }
 
-  if (!this->headerRead) {
+  if (dinfo->global_state <= DSTATE_START) {
     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");
+  setDecompParameters(this);
+  if (this->subsamp == TJSAMP_UNKNOWN)
+    THROW("Could not determine subsampling level of JPEG image");
 
-  if (jpegSubsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
-    THROW("tjDecompressToYUVPlanes(): Invalid argument");
+  if (this->subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
+    THROW("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");
+    THROW("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;
+  dinfo->scale_num = this->scalingFactor.num;
+  dinfo->scale_denom = this->scalingFactor.denom;
   jpeg_calc_output_dimensions(dinfo);
 
-  dctsize = DCTSIZE * sf[sfi].num / sf[sfi].denom;
+  dctsize = DCTSIZE * this->scalingFactor.num / this->scalingFactor.denom;
 
   for (i = 0; i < dinfo->num_components; i++) {
     jpeg_component_info *compptr = &dinfo->comp_info[i];
@@ -1718,13 +2345,13 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
 
     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);
+    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("tjDecompressToYUVPlanes(): Memory allocation failure");
+      THROW("Memory allocation failure");
     ptr = dstPlanes[i];
     for (row = 0; row < ph[i]; row++) {
       outbuf[i][row] = ptr;
@@ -1733,11 +2360,11 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
   }
   if (usetmpbuf) {
     if ((_tmpbuf = (JSAMPLE *)malloc(sizeof(JSAMPLE) * tmpbufsize)) == NULL)
-      THROW("tjDecompressToYUVPlanes(): Memory allocation failure");
+      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("tjDecompressToYUVPlanes(): Memory allocation failure");
+        THROW("Memory allocation failure");
       for (row = 0; row < th[i]; row++) {
         tmpbuf[i][row] = ptr;
         ptr += iw[i];
@@ -1750,8 +2377,8 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
     retval = -1;  goto bailout;
   }
 
-  if (flags & TJFLAG_FASTUPSAMPLE) dinfo->do_fancy_upsampling = FALSE;
-  if (flags & TJFLAG_FASTDCT) dinfo->dct_method = JDCT_FASTEST;
+  dinfo->do_fancy_upsampling = !this->fastUpsample;
+  dinfo->dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW;
   dinfo->raw_data_out = TRUE;
 
   jpeg_start_decompress(dinfo);
@@ -1763,7 +2390,7 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
     for (i = 0; i < dinfo->num_components; i++) {
       jpeg_component_info *compptr = &dinfo->comp_info[i];
 
-      if (jpegSubsamp == TJ_420) {
+      if (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
@@ -1775,8 +2402,8 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
            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->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];
       }
@@ -1806,40 +2433,36 @@ bailout:
   }
   free(_tmpbuf);
   if (this->jerr.warning) retval = -1;
-  this->jerr.stopOnWarning = FALSE;
   return retval;
 }
 
-DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
-                                 unsigned long jpegSize, unsigned char *dstBuf,
-                                 int width, int pad, int height, int flags)
+/* 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)
 {
-  unsigned char *dstPlanes[3];
-  int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
-  int i, jpegwidth, jpegheight, scaledw, scaledh;
+  static const char FUNCTION_NAME[] = "tjDecompressToYUVPlanes";
+  int i, retval = 0, jpegwidth, jpegheight, scaledw, scaledh;
 
   GET_DINSTANCE(handle);
-  this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
+  if ((this->init & DECOMPRESS) == 0)
+    THROW("Instance has not been initialized for decompression");
 
-  if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
-      pad < 1 || !IS_POW2(pad) || height < 0)
-    THROW("tjDecompressToYUV2(): Invalid argument");
+  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. */
-    return -1;
+    retval = -1;  goto bailout;
   }
 
   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]);
@@ -1847,33 +2470,129 @@ DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
       break;
   }
   if (i >= NUMSF)
-    THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
+    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+ */
+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_START) {
+    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 = tjPlaneWidth(0, width, jpegSubsamp);
-  ph0 = tjPlaneHeight(0, height, jpegSubsamp);
+  pw0 = tj3YUVPlaneWidth(0, width, this->subsamp);
+  ph0 = tj3YUVPlaneHeight(0, height, this->subsamp);
   dstPlanes[0] = dstBuf;
-  strides[0] = PAD(pw0, pad);
-  if (jpegSubsamp == TJSAMP_GRAY) {
+  strides[0] = PAD(pw0, align);
+  if (this->subsamp == 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);
+    int pw1 = tj3YUVPlaneWidth(1, width, this->subsamp);
+    int ph1 = tj3YUVPlaneHeight(1, height, this->subsamp);
 
-    strides[1] = strides[2] = PAD(pw1, pad);
+    strides[1] = strides[2] = PAD(pw1, align);
     dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
     dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
   }
 
-  this->headerRead = 1;
-  return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width,
-                                 strides, height, flags);
+  return tj3DecompressToYUVPlanes8(handle, jpegBuf, jpegSize, dstPlanes,
+                                   strides);
 
 bailout:
-  this->jerr.stopOnWarning = FALSE;
+  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)
@@ -1882,54 +2601,36 @@ DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
 }
 
 
-/* Transformer */
+/******************************** 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;
+  return tj3Init(TJINIT_TRANSFORM);
 }
 
 
-DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
-                          unsigned long jpegSize, int n,
-                          unsigned char **dstBufs, unsigned long *dstSizes,
-                          tjtransform *t, int flags)
+/* TurboJPEG 3+ */
+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, jpegSubsamp, saveMarkers = 0;
+  int retval = 0, i, 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");
+    THROW("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
+      dstSizes == NULL || t == NULL)
+    THROW("Invalid argument");
 
-  if (flags & TJFLAG_LIMITSCANS) {
+  if (this->scanLimit) {
     memset(&progress, 0, sizeof(struct my_progress_mgr));
     progress.pub.progress_monitor = my_progress_monitor;
     progress.this = this;
@@ -1939,7 +2640,7 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
 
   if ((xinfo =
        (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL)
-    THROW("tjTransform(): Memory allocation failure");
+    THROW("Memory allocation failure");
   memset(xinfo, 0, sizeof(jpeg_transform_info) * n);
 
   if (setjmp(this->jerr.setjmp_buffer)) {
@@ -1947,7 +2648,8 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
     retval = -1;  goto bailout;
   }
 
-  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+  if (dinfo->global_state <= DSTATE_START)
+    jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
 
   for (i = 0; i < n; i++) {
     xinfo[i].transform = xformtypes[t[i].op];
@@ -1974,25 +2676,22 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
   }
 
   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");
+  if (dinfo->global_state <= DSTATE_START)
+    jpeg_read_header(dinfo, TRUE);
+  this->subsamp = getSubsamp(&this->dinfo);
 
   for (i = 0; i < n; i++) {
     if (!jtransform_request_workspace(dinfo, &xinfo[i]))
-      THROW("tjTransform(): Transform is not perfect");
+      THROW("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;
-      }
+      if (this->subsamp == TJSAMP_UNKNOWN)
+        THROW("Could not determine subsampling level of JPEG image");
+      if ((t[i].r.x % tjMCUWidth[this->subsamp]) != 0 ||
+          (t[i].r.y % tjMCUHeight[this->subsamp]) != 0)
+        THROWI("To crop this JPEG image, x must be a multiple of %d\n"
+               "and y must be a multiple of %d.", tjMCUWidth[this->subsamp],
+               tjMCUHeight[this->subsamp]);
     }
   }
 
@@ -2003,18 +2702,30 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
 
     if (!xinfo[i].crop) {
       w = dinfo->image_width;  h = dinfo->image_height;
+      if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
+          t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
+        w = dinfo->image_height;  h = dinfo->image_width;
+      }
     } else {
       w = xinfo[i].crop_width;  h = xinfo[i].crop_height;
     }
-    if (flags & TJFLAG_NOREALLOC) {
-      alloc = FALSE;  dstSizes[i] = tjBufSize(w, h, jpegSubsamp);
+    if (this->noRealloc) {
+      alloc = FALSE;  dstSizes[i] = tj3JPEGBufSize(w, h, this->subsamp);
     }
     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 (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
+    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;
+    }
     if (!(t[i].options & TJXOPT_NOOUTPUT)) {
       jpeg_write_coefficients(cinfo, dstcoefs);
       jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
@@ -2044,8 +2755,8 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
 
           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");
+                                  i, (tjtransform *)&t[i]) == -1)
+              THROW("Error in custom filter");
             arrayRegion.y += DCTSIZE;
           }
         }
@@ -2064,185 +2775,92 @@ bailout:
   if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo);
   free(xinfo);
   if (this->jerr.warning) retval = -1;
-  this->jerr.stopOnWarning = FALSE;
   return retval;
 }
 
-
-DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
-                                     int align, int *height, int *pixelFormat,
-                                     int flags)
+/* 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)
 {
-  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;
+  static const char FUNCTION_NAME[] = "tjTransform";
+  int i, retval = 0;
+  size_t *sizes = NULL;
 
-#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");
+  GET_DINSTANCE(handle);
+  if ((this->init & DECOMPRESS) == 0)
+    THROW("Instance has not been initialized for decompression");
 
-  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 (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;
   }
 
-  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 bitmap loader");
-    invert = (flags & TJFLAG_BOTTOMUP) != 0;
-  } else
-    THROWG("tjLoadImage(): Unsupported file type");
+  jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize);
+  jpeg_read_header(dinfo, TRUE);
+  if (getSubsamp(dinfo) == TJSAMP_UNKNOWN)
+    THROW("Could not determine subsampling level of JPEG image");
+  processFlags(handle, flags, COMPRESS);
+
+  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];
+  retval = tj3Transform(handle, jpegBuf, (size_t)jpegSize, n, dstBufs, sizes,
+                        t);
+  for (i = 0; i < n; i++)
+    dstSizes[i] = (unsigned long)sizes[i];
 
-  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);
+bailout:
+  free(sizes);
+  return retval;
+}
 
-  *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");
+/*************************** Packed-Pixel Image I/O **************************/
 
-  if (setjmp(this->jerr.setjmp_buffer)) {
-    /* If we get here, the JPEG code has signaled an error. */
-    retval = -1;  goto bailout;
-  }
+/* tj3LoadImage*() is implemented in turbojpeg-mp.c */
 
-  while (cinfo->next_scanline < cinfo->image_height) {
-    int i, nlines = (*src->get_pixel_rows) (cinfo, src);
+/* 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;
 
-    for (i = 0; i < nlines; i++) {
-      unsigned char *dstptr;
-      int row;
+  if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL;
 
-      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;
-  }
+  processFlags(handle, flags, COMPRESS);
 
-  (*src->finish_input) (cinfo, src);
+  dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat);
 
-bailout:
-  if (handle) tjDestroy(handle);
-  if (file) fclose(file);
-  if (retval < 0) { free(dstBuf);  dstBuf = NULL; }
+  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)
 {
-  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;
+  int retval = -1;
 
-  if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 ||
-      pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
-    THROWG("tjSaveImage(): Invalid argument");
+  if ((handle = tj3Init(TJINIT_DECOMPRESS)) == NULL) return -1;
 
-  if ((handle = tjInitDecompress()) == NULL)
-    return -1;
-  this = (tjinstance *)handle;
-  dinfo = &this->dinfo;
+  processFlags(handle, flags, DECOMPRESS);
 
-#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");
+  retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height,
+                         pixelFormat);
 
-  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);
+  tj3Destroy(handle);
   return retval;
 }
index 02b54ca..12efcbc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2009-2015, 2017, 2020-2021 D. R. Commander.
+ * Copyright (C)2009-2015, 2017, 2020-2023 D. R. Commander.
  *                                         All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,8 @@
 #ifndef __TURBOJPEG_H__
 #define __TURBOJPEG_H__
 
+#include <stddef.h>
+
 #if defined(_WIN32) && defined(DLLDEFINE)
 #define DLLEXPORT  __declspec(dllexport)
 #else
  * Each plane is simply a 2D array of bytes, each byte representing the value
  * of one of the components (Y, Cb, or Cr) at a particular location in the
  * image.  The width and height of each plane are determined by the image
- * width, height, and level of chrominance subsampling.   The luminance plane
+ * width, height, and level of chrominance subsampling.  The luminance plane
  * width is the image width padded to the nearest multiple of the horizontal
- * subsampling factor (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
- * 4:1:1, 1 in the case of 4:4:4 or grayscale.)  Similarly, the luminance plane
- * height is the image height padded to the nearest multiple of the vertical
- * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
- * or grayscale.)  This is irrespective of any additional padding that may be
- * specified as an argument to the various YUV functions.  The chrominance
- * plane width is equal to the luminance plane width divided by the horizontal
- * subsampling factor, and the chrominance plane height is equal to the
- * luminance plane height divided by the vertical subsampling factor.
+ * subsampling factor (1 in the case of 4:4:4, grayscale, 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 line padding of
- * 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
- * each of the chrominance planes would be 20 x 35 bytes.
+ * chrominance planes would be 18 x 35 bytes.  If you specify a row alignment
+ * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes,
+ * and each of the chrominance planes would be 20 x 35 bytes.
  *
  * @{
  */
 
 
 /**
+ * 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  6
+#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 clarity
- * (the human eye is more sensitive to small changes in brightness than to
+ * to produce a smaller image with little perceptible loss of image clarity.
+ * (The human eye is more sensitive to small changes in brightness than to
  * small changes in color.)  This is called "chrominance subsampling".
  */
 enum TJSAMP {
@@ -96,7 +124,7 @@ enum TJSAMP {
    * YUV image will contain one chrominance component for every pixel in the
    * source image.
    */
-  TJSAMP_444 = 0,
+  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.
@@ -129,7 +157,28 @@ enum TJSAMP {
    *
    * @note 4:1:1 subsampling is not fully accelerated in libjpeg-turbo.
    */
-  TJSAMP_411
+  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.
+   * JPEG images compressed with 4:4: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: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, or
+   * - partially decompressed using a cropping region.
+   */
+  TJSAMP_UNKNOWN = -1
 };
 
 /**
@@ -140,8 +189,9 @@ enum TJSAMP {
  * - 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 };
+static const int tjMCUWidth[TJ_NUMSAMP]  = { 8, 16, 16, 8, 8, 32, 8 };
 
 /**
  * MCU block height (in pixels) for a given level of chrominance subsampling.
@@ -151,8 +201,9 @@ static const int tjMCUWidth[TJ_NUMSAMP]  = { 8, 16, 16, 8, 8, 32 };
  * - 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 };
+static const int tjMCUHeight[TJ_NUMSAMP] = { 8, 8, 16, 8, 16, 8, 32 };
 
 
 /**
@@ -166,71 +217,72 @@ static const int tjMCUHeight[TJ_NUMSAMP] = { 8, 8, 16, 8, 16, 8 };
 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.
+   * stored in 3-sample pixels in the order R, G, B from lowest to highest
+   * memory address within each pixel.
    */
-  TJPF_RGB = 0,
+  TJPF_RGB,
   /**
    * 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.
+   * 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-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.
+   * 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 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.
+   * 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 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.
+   * 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 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.
+   * 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 and undefined when decompressing.
    */
   TJPF_XRGB,
   /**
-   * Grayscale pixel format.  Each 1-byte pixel represents a luminance
-   * (brightness) level from 0 to 255.
+   * Grayscale pixel format.  Each 1-sample pixel represents a luminance
+   * (brightness) level from 0 to the maximum sample value (255 for 8-bit
+   * samples, 4095 for 12-bit samples, and 65535 for 16-bit samples.)
    */
   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.
+   * decompressing, 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, the X component is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, 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, the X component is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, 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, the X component is guaranteed to be 0xFF, which can be
-   * interpreted as an opaque alpha channel.
+   * decompressing, the X component is guaranteed to be equal to the maximum
+   * sample value, which can be interpreted as an opaque alpha channel.
    */
   TJPF_ARGB,
   /**
@@ -245,60 +297,63 @@ enum TJPF {
    * vice versa, but the mapping is typically not 1:1 or reversible, nor can it
    * be defined with a simple formula.  Thus, such a conversion is out of scope
    * for a codec library.  However, the TurboJPEG API allows for compressing
-   * CMYK pixels into a YCCK JPEG image (see #TJCS_YCCK) and decompressing YCCK
-   * JPEG images into CMYK pixels.
+   * packed-pixel CMYK images into YCCK JPEG images (see #TJCS_YCCK) and
+   * decompressing YCCK JPEG images into packed-pixel CMYK images.
    */
   TJPF_CMYK,
   /**
-   * Unknown pixel format.  Currently this is only used by #tjLoadImage().
+   * Unknown pixel format.  Currently this is only used by #tj3LoadImage8(),
+   * #tj3LoadImage12(), and #tj3LoadImage16().
    */
   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 TJ_BGRX is stored in <tt>char pixel[]</tt>,
- * then the red component will be <tt>pixel[tjRedOffset[TJ_BGRX]]</tt>.  This
- * will be -1 if the pixel format does not have a red component.
+ * 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 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 TJ_BGRX is stored in
- * <tt>char pixel[]</tt>, then the green component will be
- * <tt>pixel[tjGreenOffset[TJ_BGRX]]</tt>.  This will be -1 if the pixel format
- * does not have a green component.
+ * 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 will be
+ * `pixel[tjGreenOffset[TJPF_BGRX]]`.  This will be -1 if the pixel format does
+ * not have a green component.
  */
 static const int tjGreenOffset[TJ_NUMPF] = {
   1, 1, 1, 1, 2, 2, -1, 1, 1, 2, 2, -1
 };
 /**
- * Blue offset (in bytes) for a given pixel format.  This specifies the number
- * of bytes that the Blue component is offset from the start of the pixel.  For
- * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
- * then the blue component will be <tt>pixel[tjBlueOffset[TJ_BGRX]]</tt>.  This
- * will be -1 if the pixel format does not have a blue component.
+ * 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 will be
+ * `pixel[tjBlueOffset[TJPF_BGRX]]`.  This will be -1 if the pixel format does
+ * not have a blue component.
  */
 static const int tjBlueOffset[TJ_NUMPF] = {
   2, 0, 2, 0, 1, 3, -1, 2, 0, 1, 3, -1
 };
 /**
- * Alpha offset (in bytes) for a given pixel format.  This specifies the number
- * of bytes that the Alpha component is offset from the start of the pixel.
- * For instance, if a pixel of format TJ_BGRA is stored in
- * <tt>char pixel[]</tt>, then the alpha component will be
- * <tt>pixel[tjAlphaOffset[TJ_BGRA]]</tt>.  This will be -1 if the pixel format
- * does not have an alpha component.
+ * 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 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
+ * 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
@@ -318,10 +373,11 @@ enum TJCS {
    * RGB colorspace.  When compressing the JPEG image, the R, G, and B
    * components in the source image are reordered into image planes, but no
    * colorspace conversion or subsampling is performed.  RGB JPEG images can be
-   * decompressed to any of the extended RGB pixel formats or grayscale, but
-   * they cannot be decompressed to YUV images.
+   * compressed from and decompressed to packed-pixel images with any of the
+   * extended RGB or grayscale pixel formats, but they cannot be compressed
+   * from or decompressed to planar YUV images.
    */
-  TJCS_RGB = 0,
+  TJCS_RGB,
   /**
    * YCbCr colorspace.  YCbCr is not an absolute colorspace but rather a
    * mathematical transformation of RGB designed solely for storage and
@@ -332,25 +388,28 @@ enum TJCS {
    * original image.  Originally, the analog equivalent of this transformation
    * allowed the same signal to drive both black & white and color televisions,
    * but JPEG images use YCbCr primarily because it allows the color data to be
-   * optionally subsampled for the purposes of reducing bandwidth or disk
-   * space.  YCbCr is the most common JPEG colorspace, and YCbCr JPEG images
-   * can be compressed from and decompressed to any of the extended RGB pixel
-   * formats or grayscale, or they can be decompressed to YUV planar images.
+   * optionally subsampled for the purposes of reducing network or disk usage.
+   * YCbCr is the most common JPEG colorspace, and YCbCr JPEG images can be
+   * compressed from and decompressed to packed-pixel images with any of the
+   * extended RGB or grayscale pixel formats.  YCbCr JPEG images can also be
+   * compressed from and decompressed to planar YUV images.
    */
   TJCS_YCbCr,
   /**
    * Grayscale colorspace.  The JPEG image retains only the luminance data (Y
    * component), and any color data from the source image is discarded.
-   * Grayscale JPEG images can be compressed from and decompressed to any of
-   * the extended RGB pixel formats or grayscale, or they can be decompressed
-   * to YUV planar images.
+   * Grayscale JPEG images can be compressed from and decompressed to
+   * packed-pixel images with any of the extended RGB or grayscale pixel
+   * formats, or they can be compressed from and decompressed to planar YUV
+   * images.
    */
   TJCS_GRAY,
   /**
    * CMYK colorspace.  When compressing the JPEG image, the C, M, Y, and K
    * components in the source image are reordered into image planes, but no
    * colorspace conversion or subsampling is performed.  CMYK JPEG images can
-   * only be decompressed to CMYK pixels.
+   * only be compressed from and decompressed to packed-pixel images with the
+   * CMYK pixel format.
    */
   TJCS_CMYK,
   /**
@@ -360,75 +419,347 @@ enum TJCS {
    * reversibly transformed into YCCK, and as with YCbCr, the chrominance
    * components in the YCCK pixels can be subsampled without incurring major
    * perceptual loss.  YCCK JPEG images can only be compressed from and
-   * decompressed to CMYK pixels.
+   * decompressed to packed-pixel images with the CMYK pixel format.
    */
   TJCS_YCCK
 };
 
 
 /**
- * The uncompressed source/destination image is stored in bottom-up (Windows,
- * OpenGL) order, not top-down (X11) order.
- */
-#define TJFLAG_BOTTOMUP  2
-/**
- * When decompressing an image that was compressed using chrominance
- * subsampling, use the fastest chrominance upsampling algorithm available in
- * the underlying codec.  The default is to use smooth upsampling, which
- * creates a smooth transition between neighboring chrominance components in
- * order to reduce upsampling artifacts in the decompressed image.
- */
-#define TJFLAG_FASTUPSAMPLE  256
-/**
- * Disable buffer (re)allocation.  If passed to one of the JPEG compression or
- * transform functions, this flag will cause those functions to generate an
- * error if the JPEG image buffer is invalid or too small rather than
- * attempting to allocate or reallocate that buffer.  This reproduces the
- * behavior of earlier versions of TurboJPEG.
- */
-#define TJFLAG_NOREALLOC  1024
-/**
- * Use the fastest DCT/IDCT algorithm available in the underlying codec.  The
- * default if this flag is not specified is implementation-specific.  For
- * example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
- * algorithm by default when compressing, because this has been shown to have
- * only a very slight effect on accuracy, but it uses the accurate algorithm
- * when decompressing, because this has been shown to have a larger effect.
+ * The number of parameters
  */
-#define TJFLAG_FASTDCT  2048
-/**
- * Use the most accurate DCT/IDCT algorithm available in the underlying codec.
- * The default if this flag is not specified is implementation-specific.  For
- * example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
- * algorithm by default when compressing, because this has been shown to have
- * only a very slight effect on accuracy, but it uses the accurate algorithm
- * when decompressing, because this has been shown to have a larger effect.
- */
-#define TJFLAG_ACCURATEDCT  4096
-/**
- * Immediately discontinue the current compression/decompression/transform
- * operation if the underlying codec throws a warning (non-fatal error).  The
- * default behavior is to allow the operation to complete unless a fatal error
- * is encountered.
- */
-#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
+#define TJ_NUMPARAM
+
 /**
- * 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>.
+ * Parameters
  */
-#define TJFLAG_LIMITSCANS  32768
+enum TJPARAM {
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  TJPARAM_MAXPIXELS = -1,
+#endif
+  /**
+   * 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,
+  /**
+   * JPEG data precision (bits per sample) [decompression only, read-only]
+   *
+   * The JPEG image uses the specified number of bits per sample.
+   *
+   * **Value**
+   * - `8`, `12`, or `16`
+   *
+   * 12-bit 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 compressed 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.
+   * - The "fast" algorithm degrades and is not fully accelerated for JPEG
+   * quality levels above 97, so it will be slower than the "accurate"
+   * algorithm.
+   */
+  TJPARAM_FASTDCT,
+  /**
+   * Optimized baseline entropy coding [lossy compression only]
+   *
+   * **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.
+   *
+   * Optimized baseline entropy coding will improve compression slightly
+   * (generally 5% or less), but it will reduce compression performance
+   * considerably.
+   */
+  TJPARAM_OPTIMIZE,
+  /**
+   * Progressive entropy coding
+   *
+   * **Value**
+   * - `0` *[default for compression, lossless transformation]* The lossy JPEG
+   * image uses (decompression) or will use (compression, lossless
+   * transformation) baseline entropy coding.
+   * - `1` The lossy JPEG image uses (decompression) or will use (compression,
+   * lossless transformation) progressive entropy coding.  For lossless
+   * transformation, this can also be specified using #TJXOPT_PROGRESSIVE.
+   *
+   * Progressive entropy coding will generally improve compression relative to
+   * baseline entropy coding, but it will reduce compression and decompression
+   * performance considerably.  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 will cause the decompression and transform
+   * functions to return an error if the number of scans in a progressive JPEG
+   * image exceeds the specified limit.  The primary purpose of this is to
+   * allow security-critical applications to guard against an exploit of the
+   * progressive JPEG format described in
+   * <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 will generally improve compression relative to
+   * Huffman entropy coding, but it will reduce compression and decompression
+   * performance considerably.  Can be combined with #TJPARAM_PROGRESSIVE.
+   */
+  TJPARAM_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, compressing and decompressing lossless JPEG images is
+   * considerably slower than compressing and decompressing lossy JPEG images.
+   * 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 entropy coding
+   * - 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`]*
+   *
+   * @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 MCU blocks (lossy) or samples (lossless)
+   * [compression only]
+   *
+   * 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.
+   *
+   * **Value**
+   * - the number of MCU blocks or samples 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 (lossy) or sample rows (lossless)
+   * [compression only]
+   *
+   * See #TJPARAM_RESTARTBLOCKS for a description of restart markers.
+   *
+   * **Value**
+   * - the number of MCU rows or sample 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_DENSITYUNIT
+   * is `2`.
+   *
+   * @see TJPARAM_DENSITYUNIT
+   */
+  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_DENSITYUNIT
+   * is `2`.
+   *
+   * @see TJPARAM_DENSITYUNIT
+   */
+  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`.
+   *
+   * @see TJPARAM_XDENSITY, TJPARAM_YDENSITY
+   */
+  TJPARAM_DENSITYUNITS
+};
 
 
 /**
@@ -441,10 +772,10 @@ enum TJCS {
  */
 enum TJERR {
   /**
-   * The error was non-fatal and recoverable, but the image may still be
-   * corrupt.
+   * The error was non-fatal and recoverable, but the destination image may
+   * still be corrupt.
    */
-  TJERR_WARNING = 0,
+  TJERR_WARNING,
   /**
    * The error was fatal and non-recoverable.
    */
@@ -458,13 +789,13 @@ enum TJERR {
 #define TJ_NUMXOP  8
 
 /**
- * Transform operations for #tjTransform()
+ * Transform operations for #tj3Transform()
  */
 enum TJXOP {
   /**
    * Do not transform the position of the image pixels
    */
-  TJXOP_NONE = 0,
+  TJXOP_NONE,
   /**
    * Flip (mirror) image horizontally.  This transform is imperfect if there
    * are any partial MCU blocks on the right edge (see #TJXOPT_PERFECT.)
@@ -507,54 +838,69 @@ enum TJXOP {
 
 
 /**
- * This option will cause #tjTransform() to return an error if the transform is
- * not perfect.  Lossless transforms operate on MCU blocks, whose size depends
- * on the level of chrominance subsampling used (see #tjMCUWidth
- * and #tjMCUHeight.)  If the image's width or height is not evenly divisible
- * by the MCU block size, then there will be partial MCU blocks on the right
+ * This option will cause #tj3Transform() 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
+#define TJXOPT_PERFECT  (1 << 0)
 /**
- * This option will cause #tjTransform() to discard any partial MCU blocks that
- * cannot be transformed.
+ * This option will cause #tj3Transform() to discard any partial MCU blocks
+ * that cannot be transformed.
  */
-#define TJXOPT_TRIM  2
+#define TJXOPT_TRIM  (1 << 1)
 /**
- * This option will enable lossless cropping.  See #tjTransform() for more
+ * This option will enable lossless cropping.  See #tj3Transform() for more
  * information.
  */
-#define TJXOPT_CROP  4
+#define TJXOPT_CROP  (1 << 2)
 /**
- * This option will discard the color data in the input image and produce
- * a grayscale output image.
+ * This option will discard the color data in the source image and produce a
+ * grayscale destination image.
  */
-#define TJXOPT_GRAY  8
+#define TJXOPT_GRAY  (1 << 3)
 /**
- * This option will prevent #tjTransform() from outputting a JPEG image for
- * this particular transform (this can be used in conjunction with a custom
+ * This option will prevent #tj3Transform() 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
+#define TJXOPT_NOOUTPUT  (1 << 4)
 /**
- * This option will enable progressive entropy coding in the output image
+ * This option will enable progressive entropy coding in the JPEG image
  * generated by this particular transform.  Progressive entropy coding will
  * generally improve compression relative to baseline entropy coding (the
- * default), but it will reduce compression and decompression performance
- * considerably.
+ * default), but it will reduce decompression performance considerably.
+ * Can be combined with #TJXOPT_ARITHMETIC.  Implies #TJXOPT_OPTIMIZE unless
+ * #TJXOPT_ARITHMETIC is also specified.
  */
-#define TJXOPT_PROGRESSIVE  32
+#define TJXOPT_PROGRESSIVE  (1 << 5)
 /**
- * This option will prevent #tjTransform() from copying any extra markers
- * (including EXIF and ICC profile data) from the source image to the output
- * image.
+ * This option will prevent #tj3Transform() from copying any extra markers
+ * (including EXIF and ICC profile data) from the source image to the
+ * destination image.
  */
-#define TJXOPT_COPYNONE  64
+#define TJXOPT_COPYNONE  (1 << 6)
+/**
+ * This option will enable arithmetic entropy coding in the JPEG image
+ * generated by this particular transform.  Arithmetic entropy coding will
+ * generally improve compression relative to Huffman entropy coding (the
+ * default), but it will reduce decompression performance considerably.  Can be
+ * combined with #TJXOPT_PROGRESSIVE.
+ */
+#define TJXOPT_ARITHMETIC  (1 << 7)
+/**
+ * This option will enable optimized baseline entropy coding in the JPEG image
+ * generated by this particular transform.  Optimized baseline entropy coding
+ * will improve compression slightly (generally 5% or less.)
+ */
+#define TJXOPT_OPTIMIZE  (1 << 8)
 
 
 /**
@@ -581,23 +927,28 @@ typedef struct {
    */
   int x;
   /**
-   * The upper boundary of the cropping region.  This must be evenly divisible
-   * by the MCU block height (see #tjMCUHeight.)
+   * The upper boundary of the cropping region.  For lossless transformation,
+   * 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
+   * The width of the cropping region.  Setting this to 0 is the equivalent of
    * setting it to the width of the source JPEG image - x.
    */
   int w;
   /**
-   * The height of the cropping region. Setting this to 0 is the equivalent of
+   * The height of the cropping region.  Setting this to 0 is the equivalent of
    * setting it to the height of the source JPEG image - y.
    */
   int h;
 } tjregion;
 
 /**
+ * A #tjregion structure that specifies no cropping
+ */
+static const tjregion TJUNCROPPED = { 0, 0, 0, 0 };
+
+/**
  * Lossless transform
  */
 typedef struct tjtransform {
@@ -610,7 +961,8 @@ typedef struct tjtransform {
    */
   int op;
   /**
-   * The bitwise OR of one of more of the @ref TJXOPT_CROP "transform options"
+   * The bitwise OR of one of more of the @ref TJXOPT_ARITHMETIC
+   * "transform options"
    */
   int options;
   /**
@@ -619,10 +971,10 @@ typedef struct tjtransform {
    */
   void *data;
   /**
-   * A callback function that can be used to modify the DCT coefficients
-   * after they are losslessly transformed but before they are transcoded to a
-   * new JPEG image.  This allows for custom filters or other transformations
-   * to be applied in the frequency domain.
+   * A callback function that can be used to modify the DCT coefficients after
+   * they are losslessly transformed but before they are transcoded to a new
+   * JPEG image.  This allows for custom filters or other transformations to be
+   * applied in the frequency domain.
    *
    * @param coeffs pointer to an array of transformed DCT coefficients.  (NOTE:
    * this pointer is not guaranteed to be valid once the callback returns, so
@@ -630,21 +982,21 @@ typedef struct tjtransform {
    * or library should make a copy of them within the body of the callback.)
    *
    * @param arrayRegion #tjregion structure containing the width and height of
-   * the array pointed to by <tt>coeffs</tt> as well as its offset relative to
-   * the component plane.  TurboJPEG implementations may choose to split each
+   * the array pointed to by `coeffs` as well as its offset relative to the
+   * component plane.  TurboJPEG implementations may choose to split each
    * component plane into multiple DCT coefficient arrays and call the callback
    * function once for each array.
    *
    * @param planeRegion #tjregion structure containing the width and height of
-   * the component plane to which <tt>coeffs</tt> belongs
+   * the component plane to which `coeffs` belongs
    *
-   * @param componentID ID number of the component plane to which
-   * <tt>coeffs</tt> belongs (Y, Cb, and Cr have, respectively, ID's of 0, 1,
-   * and 2 in typical JPEG images.)
+   * @param componentID ID number of the component plane to which `coeffs`
+   * belongs.  (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in
+   * typical JPEG images.)
    *
-   * @param transformID ID number of the transformed image to which
-   * <tt>coeffs</tt> belongs.  This is the same as the index of the transform
-   * in the <tt>transforms</tt> array that was passed to #tjTransform().
+   * @param transformID ID number of the transformed image to which `coeffs`
+   * belongs.  This is the same as the index of the transform in the
+   * `transforms` array that was passed to #tj3Transform().
    *
    * @param transform a pointer to a #tjtransform structure that specifies the
    * parameters and/or cropping region for this transform
@@ -652,8 +1004,8 @@ typedef struct tjtransform {
    * @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);
+                       tjregion planeRegion, int componentID, int transformID,
+                       struct tjtransform *transform);
 } tjtransform;
 
 /**
@@ -663,19 +1015,20 @@ typedef void *tjhandle;
 
 
 /**
- * Pad the given width to the nearest 32-bit boundary
- */
-#define TJPAD(width)  (((width) + 3) & (~3))
-
-/**
- * Compute the scaled value of <tt>dimension</tt> using the given scaling
- * factor.  This macro performs the integer equivalent of <tt>ceil(dimension *
- * scalingFactor)</tt>.
+ * Compute the scaled value of `dimension` using the given scaling factor.
+ * This macro performs the integer equivalent of `ceil(dimension *
+ * scalingFactor)`.
  */
 #define TJSCALED(dimension, scalingFactor) \
   (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \
    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" {
@@ -683,231 +1036,253 @@ extern "C" {
 
 
 /**
- * Create a TurboJPEG compressor instance.
+ * 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 #tjGetErrorStr2().)
+ * @return a handle to the newly-created instance, or NULL if an error occurred
+ * (see #tj3GetErrorStr().)
  */
-DLLEXPORT tjhandle tjInitCompress(void);
+DLLEXPORT tjhandle tj3Init(int initType);
 
 
 /**
- * Compress an RGB, grayscale, or CMYK image into a JPEG image.
+ * Set the value of a parameter.
  *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
+ * @param handle handle to a TurboJPEG instance
  *
- * @param srcBuf pointer to an image buffer containing RGB, grayscale, or
- * CMYK pixels to be compressed
+ * @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);
+
+
+/**
+ * Compress an 8-bit-per-sample packed-pixel RGB, grayscale, or CMYK 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 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.
  *
  * @param width width (in pixels) of the source image
  *
- * @param pitch bytes per line in the source image.  Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps.  You can also be clever and use this parameter to skip lines, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @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 an image buffer that will receive the
- * JPEG image.  TurboJPEG has the ability to reallocate the JPEG buffer
- * to accommodate the size of the JPEG image.  Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
+ * @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 <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
  * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize().  This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * #tj3JPEGBufSize().  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, <tt>*jpegSize</tt> should be set to the size of your
- * pre-allocated buffer.  In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer.  If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.)  If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
- *
- * @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)
+ * 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 #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 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into
+ * a 12-bit-per-sample JPEG image.
  *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
+ * \details \copydetails tj3Compress8()
+ */
+DLLEXPORT int tj3Compress12(tjhandle handle, const short *srcBuf, int width,
+                            int pitch, int height, int pixelFormat,
+                            unsigned char **jpegBuf, size_t *jpegSize);
+
+/**
+ * Compress a 16-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into
+ * a 16-bit-per-sample lossless JPEG image.
  *
- * @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);
+ * \details \copydetails tj3Compress8()
+ */
+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 YUV planar image into a JPEG image.
+ * Compress an 8-bit-per-sample unified planar YUV image into an
+ * 8-bit-per-sample JPEG image.
  *
- * @param handle a handle to a TurboJPEG compressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
  *
- * @param srcBuf pointer to an image buffer containing a YUV planar image to be
- * compressed.  The size of this buffer should match the value returned by
- * #tjBufSizeYUV2() for the given image width, height, padding, and level of
- * chrominance subsampling.  The Y, U (Cb), and V (Cr) image planes should be
- * stored sequentially in the source buffer (refer to @ref YUVnotes
- * "YUV Image Format Notes".)
+ * @param srcBuf pointer to a buffer containing a unified planar YUV source
+ * image to be compressed.  The size of this buffer should match the value
+ * returned by #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 MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed within TurboJPEG.
+ * buffer copy will be performed.
  *
- * @param pad the line padding used in the source image.  For instance, if each
- * line in each plane of the YUV image is padded to the nearest multiple of 4
- * bytes, then <tt>pad</tt> should be set to 4.
+ * @param align row alignment (in bytes) of the source image (must be a power
+ * of 2.)  Setting this parameter to n indicates that each row in each plane of
+ * the source image is padded to the nearest multiple of n bytes
+ * (1 = unpadded.)
  *
  * @param height height (in pixels) of the source image.  If the height is not
  * an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed within TurboJPEG.
+ * intermediate buffer copy will be performed.
  *
- * @param subsamp the level of chrominance subsampling used in the source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param jpegBuf address of a pointer to an image buffer that will receive the
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
  * JPEG image.  TurboJPEG has the ability to reallocate the JPEG buffer to
  * accommodate the size of the JPEG image.  Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
  * let TurboJPEG grow the buffer as needed,
- * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
  * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize().  This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * #tj3JPEGBufSize().  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, <tt>*jpegSize</tt> should be set to the size of your
- * pre-allocated buffer.  In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer.  If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.)  If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
- *
- * @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 pad, int height, int subsamp,
-                                unsigned char **jpegBuf,
-                                unsigned long *jpegSize, int jpegQual,
-                                int flags);
+ * 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 #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);
 
 
 /**
- * Compress a set of Y, U (Cb), and V (Cr) image planes into a JPEG image.
+ * 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 a handle to a TurboJPEG compressor or transformer instance
+ * @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
- * image to be compressed.  These planes can be contiguous or non-contiguous in
- * memory.  The size of each plane should match the value returned by
- * #tjPlaneSizeYUV() for the given image width, height, strides, and level of
- * chrominance subsampling.  Refer to @ref YUVnotes "YUV Image Format Notes"
- * for more details.
+ * source image to be compressed.  These planes can be contiguous or
+ * non-contiguous in memory.  The size of each plane should match the value
+ * returned by #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 MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed within TurboJPEG.
+ * buffer copy will be performed.
  *
  * @param strides an array of integers, each specifying the number of bytes per
- * line in the corresponding plane of the YUV source image.  Setting the stride
+ * row in the corresponding plane of the YUV source image.  Setting the stride
  * for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".)  If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to specify an arbitrary amount of line
+ * @ref YUVnotes "YUV Image Format Notes".)  If `strides` is NULL, then the
+ * strides for all planes will be set to their respective plane widths.  You
+ * can adjust the strides in order to specify an arbitrary amount of row
  * padding in each plane or to create a JPEG image from a subregion of a larger
- * YUV planar image.
+ * planar YUV image.
  *
  * @param height height (in pixels) of the source image.  If the height is not
  * an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed within TurboJPEG.
+ * intermediate buffer copy will be performed.
  *
- * @param subsamp the level of chrominance subsampling used in the source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
- *
- * @param jpegBuf address of a pointer to an image buffer that will receive the
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
  * JPEG image.  TurboJPEG has the ability to reallocate the JPEG buffer to
  * accommodate the size of the JPEG image.  Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
+ * -# pre-allocate the JPEG buffer with an arbitrary size using #tj3Alloc() and
  * let TurboJPEG grow the buffer as needed,
- * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
  * -# pre-allocate the buffer to a "worst case" size determined by calling
- * #tjBufSize().  This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * #tj3JPEGBufSize().  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, <tt>*jpegSize</tt> should be set to the size of your
- * pre-allocated buffer.  In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
- *
- * @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer.  If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.)  If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
- *
- * @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);
+ * 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 #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);
 
 
 /**
  * The maximum size of the buffer (in bytes) required to hold a JPEG image with
  * the given parameters.  The number of bytes returned by this function is
  * larger than the size of the uncompressed source image.  The reason for this
- * is that the JPEG format uses 16-bit coefficients, and it is thus possible
- * for a very high-quality JPEG image with very high-frequency content to
- * expand rather than compress when converted to the JPEG format.  Such images
- * represent a very rare corner case, but since there is no way to predict the
- * size of a JPEG image prior to compression, the corner case has to be
+ * is that the JPEG format uses 16-bit coefficients, so it is possible for a
+ * very high-quality source image with very high-frequency content to expand
+ * rather than compress when converted to the JPEG format.  Such images
+ * represent very rare corner cases, but since there is no way to predict the
+ * size of a JPEG image prior to compression, the corner cases have to be
  * handled.
  *
  * @param width width (in pixels) of the image
@@ -916,33 +1291,37 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
  *
  * @param jpegSubsamp the level of chrominance subsampling to be used when
  * generating the JPEG image (see @ref TJSAMP
- * "Chrominance subsampling options".)
+ * "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 -1 if the arguments are out of bounds.
+ * image, or 0 if the arguments are out of bounds.
  */
-DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp);
+DLLEXPORT size_t tj3JPEGBufSize(int width, int height, int jpegSubsamp);
 
 
 /**
- * The size of the buffer (in bytes) required to hold a YUV planar image with
- * the given parameters.
+ * The size of the buffer (in bytes) required to hold a unified planar YUV
+ * image with the given parameters.
  *
  * @param width width (in pixels) of the image
  *
- * @param pad the width of each line in each plane of the image is padded to
- * the nearest multiple of this number of bytes (must be a power of 2.)
+ * @param align row alignment (in bytes) of the image (must be a power of 2.)
+ * Setting this parameter to n specifies that each row in each plane of the
+ * image will be padded to the nearest multiple of n bytes (1 = unpadded.)
  *
  * @param height height (in pixels) of the image
  *
  * @param subsamp level of chrominance subsampling in the image (see
  * @ref TJSAMP "Chrominance subsampling options".)
  *
- * @return the size of the buffer (in bytes) required to hold the image, or
- * -1 if the arguments are out of bounds.
+ * @return the size of the buffer (in bytes) required to hold the image, or 0
+ * if the arguments are out of bounds.
  */
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
-                                      int subsamp);
+DLLEXPORT size_t tj3YUVBufSize(int width, int align, int height, int subsamp);
 
 
 /**
@@ -954,7 +1333,7 @@ DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
  * @param width width (in pixels) of the YUV image.  NOTE: this is the width of
  * the whole image, not the plane width.
  *
- * @param stride bytes per line in the image plane.  Setting this to 0 is the
+ * @param stride bytes per row in the image plane.  Setting this to 0 is the
  * equivalent of setting it to the plane width.
  *
  * @param height height (in pixels) of the YUV image.  NOTE: this is the height
@@ -964,10 +1343,10 @@ DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
  * @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.
+ * plane, or 0 if the arguments are out of bounds.
  */
-DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
-                                       int height, int subsamp);
+DLLEXPORT size_t tj3YUVPlaneSize(int componentID, int width, int stride,
+                                 int height, int subsamp);
 
 
 /**
@@ -981,10 +1360,10 @@ DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
  * @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.
+ * @return the plane width of a YUV image plane with the given parameters, or 0
+ * if the arguments are out of bounds.
  */
-DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp);
+DLLEXPORT int tj3YUVPlaneWidth(int componentID, int width, int subsamp);
 
 
 /**
@@ -999,86 +1378,82 @@ DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp);
  * @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.
+ * 0 if the arguments are out of bounds.
  */
-DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp);
+DLLEXPORT int tj3YUVPlaneHeight(int componentID, int height, int subsamp);
 
 
 /**
- * Encode an RGB or grayscale image into a YUV planar image.  This function
- * uses the accelerated color conversion routines in the underlying
- * codec but does not execute any of the other steps in the JPEG compression
- * process.
+ * Encode 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 a handle to a TurboJPEG compressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * compression
  *
- * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
+ * source image to be encoded.  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 line in the source image.  Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps.  You can also be clever and use this parameter to skip lines, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @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 an image buffer that will receive the YUV image.
- * Use #tjBufSizeYUV2() to determine the appropriate size for this buffer based
- * on the image width, height, padding, and level of chrominance subsampling.
- * The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the
- * buffer (refer to @ref YUVnotes "YUV Image Format Notes".)
- *
- * @param pad the width of each line in each plane of the YUV image will be
- * padded to the nearest multiple of this number of bytes (must be a power of
- * 2.)  To generate images suitable for X Video, <tt>pad</tt> should be set to
- * 4.
- *
- * @param subsamp the level of chrominance subsampling to be used when
- * generating the YUV image (see @ref TJSAMP
- * "Chrominance subsampling options".)  To generate images suitable for X
- * Video, <tt>subsamp</tt> should be set to @ref TJSAMP_420.  This produces an
- * image compatible with the I420 (AKA "YUV420P") format.
- *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
- * "flags"
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
-*/
-DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
-                           int width, int pitch, int height, int pixelFormat,
-                           unsigned char *dstBuf, int pad, int subsamp,
-                           int flags);
+ * @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);
 
 
 /**
- * Encode an RGB or grayscale image into separate Y, U (Cb), and V (Cr) image
- * planes.  This function uses the accelerated color conversion routines in the
- * underlying codec but does not execute any of the other steps in the JPEG
- * compression process.
+ * Encode 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 a handle to a TurboJPEG compressor or transformer instance
+ * @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 srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded
  *
  * @param width width (in pixels) of the source image
  *
- * @param pitch bytes per line in the source image.  Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps.  You can also be clever and use this parameter to skip lines, etc.
- * Setting this parameter to 0 is the equivalent of setting it to
- * <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @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
  *
@@ -1088,53 +1463,39 @@ DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
  * @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.
+ * 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
- * line in the corresponding plane of the output image.  Setting the stride for
- * any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".)  If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to add an arbitrary amount of line
- * padding to each plane or to encode an RGB or grayscale image into a
- * subregion of a larger YUV planar image.
- *
- * @param subsamp the level of chrominance subsampling to be used when
- * generating the YUV image (see @ref TJSAMP
- * "Chrominance subsampling options".)  To generate images suitable for X
- * Video, <tt>subsamp</tt> should be set to @ref TJSAMP_420.  This produces an
- * image compatible with the I420 (AKA "YUV420P") format.
- *
- * @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.
+ * 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 a handle to the newly-created instance, or NULL if an error
- * occurred (see #tjGetErrorStr2().)
-*/
-DLLEXPORT tjhandle tjInitDecompress(void);
+ * @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);
 
 
 /**
  * Retrieve information about a JPEG image without decompressing it, or prime
- * the decompressor with quantization and Huffman tables.
+ * 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.
  *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
  *
- * @param jpegBuf pointer to a buffer containing a JPEG image or an
+ * @param jpegBuf pointer to a byte buffer containing a JPEG image or an
  * "abbreviated table specification" (AKA "tables-only") datastream.  Passing a
  * tables-only datastream to this function primes the decompressor with
  * quantization and Huffman tables that can be used when decompressing
@@ -1144,334 +1505,328 @@ DLLEXPORT tjhandle tjInitDecompress(void);
  *
  * @param jpegSize size of the JPEG image or tables-only datastream (in bytes)
  *
- * @param width pointer to an integer variable that will receive the width (in
- * pixels) of the JPEG image.  If <tt>jpegBuf</tt> points to a tables-only
- * datastream, then <tt>width</tt> is ignored.
- *
- * @param height pointer to an integer variable that will receive the height
- * (in pixels) of the JPEG image.  If <tt>jpegBuf</tt> points to a tables-only
- * datastream, then <tt>height</tt> is ignored.
- *
- * @param jpegSubsamp pointer to an integer variable that will receive the
- * level of chrominance subsampling used when the JPEG image was compressed
- * (see @ref TJSAMP "Chrominance subsampling options".)  If <tt>jpegBuf</tt>
- * points to a tables-only datastream, then <tt>jpegSubsamp</tt> is ignored.
- *
- * @param jpegColorspace pointer to an integer variable that will receive one
- * of the JPEG colorspace constants, indicating the colorspace of the JPEG
- * image (see @ref TJCS "JPEG colorspaces".)  If <tt>jpegBuf</tt>
- * points to a tables-only datastream, then <tt>jpegColorspace</tt> is ignored.
- *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
-*/
-DLLEXPORT int tjDecompressHeader3(tjhandle handle,
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3DecompressHeader(tjhandle handle,
                                   const unsigned char *jpegBuf,
-                                  unsigned long jpegSize, int *width,
-                                  int *height, int *jpegSubsamp,
-                                  int *jpegColorspace);
+                                  size_t jpegSize);
 
 
 /**
- * Returns a list of fractional scaling factors that the JPEG decompressor in
- * this implementation of TurboJPEG supports.
+ * Returns a list of fractional scaling factors that the JPEG decompressor
+ * supports.
  *
- * @param numscalingfactors pointer to an integer variable that will receive
+ * @param numScalingFactors pointer to an integer variable that will receive
  * the number of elements in the list
  *
  * @return a pointer to a list of fractional scaling factors, or NULL if an
- * error is encountered (see #tjGetErrorStr2().)
-*/
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors);
+ * error is encountered (see #tj3GetErrorStr().)
+ */
+DLLEXPORT tjscalingfactor *tj3GetScalingFactors(int *numScalingFactors);
 
 
 /**
- * Decompress a JPEG image to an RGB, grayscale, or CMYK image.
+ * Set the scaling factor for subsequent lossy decompression operations.
  *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @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 MCU block 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.
  *
- * @param jpegSize size of the JPEG image (in bytes)
+ * @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 dstBuf pointer to an image buffer that will receive the decompressed
- * image.  This buffer should normally be <tt>pitch * scaledHeight</tt> bytes
- * in size, where <tt>scaledHeight</tt> can be determined by calling
- * #TJSCALED() with the JPEG image height and one of the scaling factors
- * returned by #tjGetScalingFactors().  The <tt>dstBuf</tt> pointer may also be
- * used to decompress into a specific region of a larger buffer.
- *
- * @param width desired width (in pixels) of the destination image.  If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width.  If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size.
- *
- * @param pitch bytes per line in the destination image.  Normally, this is
- * <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt> if the decompressed image
- * is unpadded, else <tt>#TJPAD(scaledWidth * #tjPixelSize[pixelFormat])</tt>
- * if each line of the decompressed image is padded to the nearest 32-bit
- * boundary, as is the case for Windows bitmaps.  (NOTE: <tt>scaledWidth</tt>
- * can be determined by calling #TJSCALED() with the JPEG image width and one
- * of the scaling factors returned by #tjGetScalingFactors().)  You can also be
- * clever and use the pitch parameter to skip lines, etc.  Setting this
- * parameter to 0 is the equivalent of setting it to
- * <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt>.
+ * @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
+ * MCU block 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 an 8-bit-per-sample JPEG image into an 8-bit-per-sample
+ * packed-pixel RGB, grayscale, or CMYK 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 height desired height (in pixels) of the destination image.  If this
- * is different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height.  If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size.
+ * @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".)
  *
- * @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 #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
+ */
+DLLEXPORT int tj3Decompress8(tjhandle handle, const unsigned char *jpegBuf,
+                             size_t jpegSize, unsigned char *dstBuf, int pitch,
+                             int pixelFormat);
+
+/**
+ * Decompress a 12-bit-per-sample JPEG image into a 12-bit-per-sample
+ * packed-pixel RGB, grayscale, or CMYK image.
  *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
- * and #tjGetErrorCode().)
+ * \details \copydetails tj3Decompress8()
  */
-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 tj3Decompress12(tjhandle handle, const unsigned char *jpegBuf,
+                              size_t jpegSize, short *dstBuf, int pitch,
+                              int pixelFormat);
+
+/**
+ * Decompress a 16-bit-per-sample lossless JPEG image into a 16-bit-per-sample
+ * packed-pixel RGB, grayscale, or CMYK image.
+ *
+ * \details \copydetails tj3Decompress8()
+ */
+DLLEXPORT int tj3Decompress16(tjhandle handle, const unsigned char *jpegBuf,
+                              size_t jpegSize, unsigned short *dstBuf,
+                              int pitch, int pixelFormat);
 
 
 /**
- * Decompress a JPEG image to a YUV planar image.  This function performs JPEG
- * decompression but leaves out the color conversion step, so a planar YUV
- * image is generated instead of an RGB image.
+ * Decompress 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 a handle to a TurboJPEG decompressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
- * @param dstBuf pointer to an image buffer that will receive the YUV image.
- * Use #tjBufSizeYUV2() to determine the appropriate size for this buffer based
- * on the image width, height, padding, and level of subsampling.  The Y,
- * U (Cb), and V (Cr) image planes will be stored sequentially in the buffer
- * (refer to @ref YUVnotes "YUV Image Format Notes".)
- *
- * @param width desired width (in pixels) of the YUV image.  If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width.  If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size.  If the scaled width is not an even multiple of the MCU
- * block width (see #tjMCUWidth), then an intermediate buffer copy will be
- * performed within TurboJPEG.
- *
- * @param pad the width of each line in each plane of the YUV image will be
- * padded to the nearest multiple of this number of bytes (must be a power of
- * 2.)  To generate images suitable for X Video, <tt>pad</tt> should be set to
- * 4.
- *
- * @param height desired height (in pixels) of the YUV image.  If this is
- * different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height.  If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size.  If the scaled height is not an even multiple of the MCU
- * block height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed within TurboJPEG.
- *
- * @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().)
+ * @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 tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
-                                 unsigned long jpegSize, unsigned char *dstBuf,
-                                 int width, int pad, int height, int flags);
+DLLEXPORT int tj3DecompressToYUV8(tjhandle handle,
+                                  const unsigned char *jpegBuf,
+                                  size_t jpegSize,
+                                  unsigned char *dstBuf, int align);
 
 
 /**
- * Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image
- * planes.  This function performs JPEG decompression but leaves out the color
- * conversion step, so a planar YUV image is generated instead of an RGB image.
+ * 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 a handle to a TurboJPEG decompressor or transformer instance
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
  * @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
  * (or just a Y plane, if decompressing a grayscale image) that will receive
- * the YUV image.  These planes can be contiguous or non-contiguous in memory.
- * Use #tjPlaneSizeYUV() to determine the appropriate size for each plane based
- * on the scaled image width, scaled image height, strides, and level of
- * chrominance subsampling.  Refer to @ref YUVnotes "YUV Image Format Notes"
- * for more details.
- *
- * @param width desired width (in pixels) of the YUV image.  If this is
- * different than the width of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width.  If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size.  If the scaled width is not an even multiple of the MCU
- * block width (see #tjMCUWidth), then an intermediate buffer copy will be
- * performed within TurboJPEG.
+ * 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
- * line in the corresponding plane of the output image.  Setting the stride for
- * any plane to 0 is the same as setting it to the scaled plane width (see
- * @ref YUVnotes "YUV Image Format Notes".)  If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective scaled plane
- * widths.  You can adjust the strides in order to add an arbitrary amount of
- * line padding to each plane or to decompress the JPEG image into a subregion
- * of a larger YUV planar image.
- *
- * @param height desired height (in pixels) of the YUV image.  If this is
- * different than the height of the JPEG image being decompressed, then
- * TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height.  If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size.  If the scaled height is not an even multiple of the MCU
- * block height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed within TurboJPEG.
- *
- * @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().)
+ * 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 tjDecompressToYUVPlanes(tjhandle handle,
-                                      const unsigned char *jpegBuf,
-                                      unsigned long jpegSize,
-                                      unsigned char **dstPlanes, int width,
-                                      int *strides, int height, int flags);
+DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle,
+                                        const unsigned char *jpegBuf,
+                                        size_t jpegSize,
+                                        unsigned char **dstPlanes,
+                                        int *strides);
 
 
 /**
- * Decode a YUV planar image into an RGB or grayscale image.  This function
- * uses the accelerated color conversion routines in the underlying
- * codec but does not execute any of the other steps in the JPEG decompression
- * process.
- *
- * @param handle a handle to a TurboJPEG decompressor or transformer instance
+ * 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 srcBuf pointer to an image buffer containing a YUV planar image to be
- * decoded.  The size of this buffer should match the value returned by
- * #tjBufSizeYUV2() for the given image width, height, padding, and level of
- * chrominance subsampling.  The Y, U (Cb), and V (Cr) image planes should be
- * stored sequentially in the source buffer (refer to @ref YUVnotes
- * "YUV Image Format Notes".)
+ * @param handle handle to a TurboJPEG instance that has been initialized for
+ * decompression
  *
- * @param pad Use this parameter to specify that the width of each line in each
- * plane of the YUV source image is padded to the nearest multiple of this
- * number of bytes (must be a power of 2.)
+ * @param 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 subsamp the level of chrominance subsampling used in the YUV source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
+ * @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 an image buffer that will receive the decoded
- * image.  This buffer should normally be <tt>pitch * height</tt> bytes in
- * size, but the <tt>dstBuf</tt> pointer can also be used to decode into a
- * specific region of a larger buffer.
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image.  This buffer should normally be `pitch * height` bytes in size.
+ * 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 line in the destination image.  Normally, this should
- * be <tt>width * #tjPixelSize[pixelFormat]</tt> if the destination image is
- * unpadded, or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line
- * of the destination image should be padded to the nearest 32-bit boundary, as
- * is the case for Windows bitmaps.  You can also be clever and use the pitch
- * parameter to skip lines, etc.  Setting this parameter to 0 is the equivalent
- * of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @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".)
  *
- * @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().)
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
  */
-DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
-                          int pad, int subsamp, unsigned char *dstBuf,
-                          int width, int pitch, int height, int pixelFormat,
-                          int flags);
+DLLEXPORT int tj3DecodeYUV8(tjhandle handle, const unsigned char *srcBuf,
+                            int align, unsigned char *dstBuf, int width,
+                            int pitch, int height, int pixelFormat);
 
 
 /**
- * Decode a set of Y, U (Cb), and V (Cr) image planes into an RGB or grayscale
- * image.  This function uses the accelerated color conversion routines in the
- * underlying codec but does not execute any of the other steps in the JPEG
+ * 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 a handle to a TurboJPEG decompressor or transformer instance
+ * @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 #tjPlaneSizeYUV()
+ * The size of each plane should match the value returned by #tj3YUVPlaneSize()
  * for the given image width, height, strides, and level of chrominance
- * subsampling.  Refer to @ref YUVnotes "YUV Image Format Notes" for more
- * details.
+ * 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
- * line in the corresponding plane of the YUV source image.  Setting the stride
+ * row in the corresponding plane of the YUV source image.  Setting the stride
  * for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".)  If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to specify an arbitrary amount of line
- * padding in each plane or to decode a subregion of a larger YUV planar image.
- *
- * @param subsamp the level of chrominance subsampling used in the YUV source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
+ * @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 an image buffer that will receive the decoded
- * image.  This buffer should normally be <tt>pitch * height</tt> bytes in
- * size, but the <tt>dstBuf</tt> pointer can also be used to decode into a
- * specific region of a larger buffer.
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image.  This buffer should normally be `pitch * height` bytes in size.
+ * 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 line in the destination image.  Normally, this should
- * be <tt>width * #tjPixelSize[pixelFormat]</tt> if the destination image is
- * unpadded, or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line
- * of the destination image should be padded to the nearest 32-bit boundary, as
- * is the case for Windows bitmaps.  You can also be clever and use the pitch
- * parameter to skip lines, etc.  Setting this parameter to 0 is the equivalent
- * of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
+ * @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".)
  *
- * @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().)
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
  */
-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);
+DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle,
+                                  const unsigned char * const *srcPlanes,
+                                  const int *strides, unsigned char *dstBuf,
+                                  int width, int pitch, int height,
+                                  int pixelFormat);
 
 
 /**
@@ -1480,226 +1835,256 @@ DLLEXPORT tjhandle tjInitTransform(void);
  * 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
+ * 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.
+ * 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 handle handle to a TurboJPEG instance that has been initialized for
+ * lossless transformation
  *
- * @param jpegBuf pointer to a buffer containing the JPEG source image to
+ * @param jpegBuf pointer to a byte buffer containing the JPEG source image to
  * transform
  *
  * @param jpegSize size of the JPEG source image (in bytes)
  *
  * @param n the number of transformed JPEG images to generate
  *
- * @param dstBufs pointer to an array of n image buffers.  <tt>dstBufs[i]</tt>
- * will receive a JPEG image that has been transformed using the parameters in
- * <tt>transforms[i]</tt>.  TurboJPEG has the ability to reallocate the JPEG
- * buffer to accommodate the size of the JPEG image.  Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
- * let TurboJPEG grow the buffer as needed,
- * -# set <tt>dstBufs[i]</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * @param dstBufs pointer to an array of n byte buffers.  `dstBufs[i]` will
+ * receive a JPEG image that has been transformed using the parameters in
+ * `transforms[i]`.  TurboJPEG has the ability to reallocate the JPEG
+ * destination buffer to accommodate the size of the transformed JPEG image.
+ * Thus, you can choose to:
+ * -# pre-allocate the JPEG destination buffer with an arbitrary size using
+ * #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
- * #tjBufSize() with the transformed or cropped width and height.  Under normal
- * circumstances, this should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)  Note,
- * however, that there are some rare cases (such as transforming images with a
- * large amount of embedded EXIF or ICC profile data) in which the output image
- * will be larger than the worst-case size, and #TJFLAG_NOREALLOC cannot be
- * used in those cases.
+ * #tj3JPEGBufSize() with the transformed or cropped width and height and the
+ * level of subsampling used in the source image.  Under normal circumstances,
+ * this should ensure that the buffer never has to be re-allocated.  (Setting
+ * #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 or ICC profile data) in which the transformed JPEG image will
+ * be larger than the worst-case size, and #TJPARAM_NOREALLOC cannot be used in
+ * those cases.
  * .
- * If you choose option 1, <tt>dstSizes[i]</tt> should be set to the size of
- * your pre-allocated buffer.  In any case, unless you have set
- * #TJFLAG_NOREALLOC, you should always check <tt>dstBufs[i]</tt> upon return
- * from this function, as it may have changed.
+ * If you choose option 1, then `dstSizes[i]` should be set to the size of your
+ * pre-allocated buffer.  In any case, unless you have set #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 unsigned long variables that will
- * receive the actual sizes (in bytes) of each transformed JPEG image.  If
- * <tt>dstBufs[i]</tt> points to a pre-allocated buffer, then
- * <tt>dstSizes[i]</tt> should be set to the size of the buffer.  Upon return,
- * <tt>dstSizes[i]</tt> will contain the size of the JPEG image (in bytes.)
+ * @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 output image.
+ * 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().)
+ * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr()
+ * and #tj3GetErrorCode().)
  */
-DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
-                          unsigned long jpegSize, int n,
-                          unsigned char **dstBufs, unsigned long *dstSizes,
-                          tjtransform *transforms, int flags);
+DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf,
+                           size_t jpegSize, int n, unsigned char **dstBufs,
+                           size_t *dstSizes, const tjtransform *transforms);
 
 
 /**
- * Destroy a TurboJPEG compressor, decompressor, or transformer instance.
+ * Destroy a TurboJPEG 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().)
+ * @param handle handle to a TurboJPEG instance.  If the handle is NULL, then
+ * this function has no effect.
  */
-DLLEXPORT int tjDestroy(tjhandle handle);
+DLLEXPORT void tj3Destroy(tjhandle handle);
 
 
 /**
- * Allocate an image buffer for use with TurboJPEG.  You should always use
- * this function to allocate the JPEG destination buffer(s) for the compression
- * and transform functions unless you are disabling automatic buffer
- * (re)allocation (by setting #TJFLAG_NOREALLOC.)
+ * Allocate a byte buffer for use with TurboJPEG.  You should always use this
+ * function to allocate the JPEG destination buffer(s) for the compression and
+ * transform functions unless you are disabling automatic buffer (re)allocation
+ * (by setting #TJPARAM_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()
+ * @see tj3Free()
  */
-DLLEXPORT unsigned char *tjAlloc(int bytes);
+DLLEXPORT void *tj3Alloc(size_t bytes);
 
 
 /**
- * Load an uncompressed image from disk into memory.
+ * Load an 8-bit-per-sample packed-pixel image from disk into memory.
  *
- * @param filename name of a file containing an uncompressed image in Windows
- * BMP or PBMPLUS (PPM/PGM) format
+ * @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.  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 uncompressed image
+ * pixels) of the packed-pixel image
  *
- * @param align row alignment of the image buffer to be returned (must be a
- * power of 2.)  For instance, setting this parameter to 4 will cause all rows
- * in the image buffer to be padded to the nearest 32-bit boundary, and setting
- * this parameter to 1 will cause all rows in the image buffer to be unpadded.
+ * @param align row alignment (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 uncompressed image
+ * (in pixels) of the packed-pixel image
  *
  * @param pixelFormat pointer to an integer variable that specifies or will
- * receive the pixel format of the uncompressed image buffer.  The behavior of
- * #tjLoadImage() will vary depending on the value of <tt>*pixelFormat</tt>
- * passed to the function:
- * - @ref TJPF_UNKNOWN : The uncompressed image buffer returned by the function
- * will use the most optimal pixel format for the file type, and
- * <tt>*pixelFormat</tt> will contain the ID of this pixel format upon
- * successful return from the function.
- * - @ref TJPF_GRAY : Only PGM files and 8-bit BMP files with a grayscale
- * colormap can be loaded.
+ * receive the pixel format of the packed-pixel buffer.  The behavior of 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 and 8-bit-per-pixel BMP files with a
+ * grayscale colormap can be loaded.
  * - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
  * converted using a quick & dirty algorithm that is suitable only for testing
- * purposes (proper conversion between CMYK and other formats requires a color
- * management system.)
- * - Other @ref TJPF "pixel formats" : The uncompressed image buffer will use
- * the specified pixel format, and pixel format conversion will be performed if
+ * purposes.  (Proper conversion between CMYK and other formats requires a
+ * color management system.)
+ * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
+ * specified pixel format, and pixel format conversion will be performed if
  * necessary.
  *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
- * "flags".
- *
- * @return a pointer to a newly-allocated buffer containing the uncompressed
+ * @return a pointer to a newly-allocated buffer containing the packed-pixel
  * image, converted to the chosen pixel format and with the chosen row
- * alignment, or NULL if an error occurred (see #tjGetErrorStr2().)  This
- * buffer should be freed using #tjFree().
+ * alignment, or NULL if an error occurred (see #tj3GetErrorStr().)  This
+ * buffer should be freed using #tj3Free().
  */
-DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
-                                     int align, int *height, int *pixelFormat,
-                                     int flags);
+DLLEXPORT unsigned char *tj3LoadImage8(tjhandle handle, const char *filename,
+                                       int *width, int align, int *height,
+                                       int *pixelFormat);
+
+/**
+ * Load a 12-bit-per-sample packed-pixel image from disk into memory.
+ *
+ * \details \copydetails tj3LoadImage8()
+ */
+DLLEXPORT short *tj3LoadImage12(tjhandle handle, const char *filename,
+                                int *width, int align, int *height,
+                                int *pixelFormat);
+
+/**
+ * Load a 16-bit-per-sample packed-pixel image from disk into memory.
+ *
+ * \details \copydetails tj3LoadImage8()
+ */
+DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename,
+                                         int *width, int align, int *height,
+                                         int *pixelFormat);
 
 
 /**
- * Save an uncompressed image from memory to disk.
+ * Save an 8-bit-per-sample packed-pixel image from memory to disk.
  *
- * @param filename name of a file to which to save the uncompressed image.
- * The image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format,
- * depending on the file extension.
+ * @param handle handle to a TurboJPEG instance
  *
- * @param buffer pointer to an image buffer containing RGB, grayscale, or
- * CMYK pixels to be saved
+ * @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.
  *
- * @param width width (in pixels) of the uncompressed image
+ * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK image to be saved
  *
- * @param pitch bytes per line in the image buffer.  Setting this parameter to
- * 0 is the equivalent of setting it to
+ * @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 uncompressed image
+ * @param height height (in pixels) of the packed-pixel image
  *
- * @param pixelFormat pixel format of the image buffer (see @ref TJPF
+ * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
  * "Pixel formats".)  If this parameter is set to @ref TJPF_GRAY, then the
- * image will be stored in PGM or 8-bit (indexed color) BMP format.  Otherwise,
- * the image will be stored in PPM or 24-bit BMP format.  If this parameter
- * is set to @ref TJPF_CMYK, then the CMYK pixels will be converted to RGB
- * using a quick & dirty algorithm that is suitable only for testing (proper
- * conversion between CMYK and other formats requires a color management
- * system.)
+ * image will be stored in PGM or 8-bit-per-pixel (indexed color) BMP format.
+ * Otherwise, the image will be stored in PPM or 24-bit-per-pixel BMP format.
+ * If this parameter is set to @ref TJPF_CMYK, then the CMYK pixels will be
+ * converted to RGB using a quick & dirty algorithm that is suitable only for
+ * testing purposes.  (Proper conversion between CMYK and other formats
+ * requires a color management system.)
+ *
+ * @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 12-bit-per-sample packed-pixel image from memory to disk.
  *
- * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
- * "flags".
+ * \details \copydetails tj3SaveImage8()
+ */
+DLLEXPORT int tj3SaveImage12(tjhandle handle, const char *filename,
+                             const short *buffer, int width, int pitch,
+                             int height, int pixelFormat);
+
+/**
+ * Save a 16-bit-per-sample packed-pixel image from memory to disk.
  *
- * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2().)
+ * \details \copydetails tj3SaveImage8()
  */
-DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
-                          int width, int pitch, int height, int pixelFormat,
-                          int flags);
+DLLEXPORT int tj3SaveImage16(tjhandle handle, const char *filename,
+                             const unsigned short *buffer, int width,
+                             int pitch, int height, int pixelFormat);
 
 
 /**
- * Free an image buffer previously allocated by TurboJPEG.  You should always
- * use this function to free JPEG destination buffer(s) that were automatically
+ * Free a byte buffer previously allocated by TurboJPEG.  You should always use
+ * this function to free JPEG destination buffer(s) that were automatically
  * (re)allocated by the compression and transform functions or that were
- * manually allocated using #tjAlloc().
+ * manually allocated using #tj3Alloc().
  *
  * @param buffer address of the buffer to free.  If the address is NULL, then
  * this function has no effect.
  *
- * @sa tjAlloc()
+ * @see tj3Alloc()
  */
-DLLEXPORT void tjFree(unsigned char *buffer);
+DLLEXPORT void tj3Free(void *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.)
+ * @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 *tjGetErrorStr2(tjhandle handle);
+DLLEXPORT char *tj3GetErrorStr(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
+ * @param handle handle to a TurboJPEG instance
  *
  * @return a code indicating the severity of the last error.  See
  * @ref TJERR "Error codes".
  */
-DLLEXPORT int tjGetErrorCode(tjhandle handle);
+DLLEXPORT int tj3GetErrorCode(tjhandle handle);
 
 
-/* Deprecated functions and macros */
-#define TJFLAG_FORCEMMX  8
-#define TJFLAG_FORCESSE  16
-#define TJFLAG_FORCESSE2  32
-#define TJFLAG_FORCESSE3  128
+/* Backward compatibility functions and macros (nothing to see here) */
 
+/* TurboJPEG 1.0+ */
 
-/* Backward compatibility functions and macros (nothing to see here) */
 #define NUMSUBOPT  TJ_NUMSAMP
 #define TJ_444  TJSAMP_444
 #define TJ_422  TJSAMP_422
@@ -1715,46 +2100,180 @@ DLLEXPORT int tjGetErrorCode(tjhandle handle);
 #define TJ_ALPHAFIRST  64
 #define TJ_FORCESSE3  TJFLAG_FORCESSE3
 #define TJ_FASTUPSAMPLE  TJFLAG_FASTUPSAMPLE
-#define TJ_YUV  512
 
-DLLEXPORT unsigned long TJBUFSIZE(int width, int height);
-
-DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp);
+#define TJPAD(width)  (((width) + 3) & (~3))
 
-DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp);
+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 int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
-                                 unsigned long jpegSize, int *width,
-                                 int *height);
+DLLEXPORT void tjFree(unsigned char *buffer);
 
-DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
+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 *height, int *jpegSubsamp,
+                                  int *jpegColorspace);
 
-DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
-                           unsigned long jpegSize, unsigned char *dstBuf,
-                           int width, int pitch, int height, int pixelSize,
+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 tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
-                                unsigned long jpegSize, unsigned char *dstBuf,
-                                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 char *tjGetErrorStr(void);
+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
 
 /**
  * @}
index 0b6036a..c1bba4a 100644 (file)
--- a/usage.txt
+++ b/usage.txt
@@ -160,6 +160,39 @@ file size is about the same --- often a little smaller.
 
 Switches for advanced users:
 
+        -precision N   Create JPEG file with N-bit data precision.
+                       N is 8, 12, or 16; default is 8.  If N is 16, then
+                       -lossless must also be specified.  CAUTION: 12-bit and
+                       16-bit JPEG is not yet widely implemented, so many
+                       decoders will be unable to view a 12-bit or 16-bit JPEG
+                       file at all.
+
+        -lossless psv[,Pt] Create a lossless JPEG file using the specified
+                        predictor selection value (1 - 7) and optional point
+                        transform (0 - {precision}-1, where {precision} is the
+                        JPEG data precision in bits).  A point transform value
+                        of 0 (the default) is necessary in order to create a
+                        fully lossless JPEG file.  (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.)  CAUTION: lossless JPEG is not yet
+                        widely implemented, so many decoders will be unable to
+                        view a lossless JPEG file at all.  Note that the
+                        following features will be unavailable when compressing
+                        or decompressing a lossless JPEG file:
+                          * Quality/quantization table selection
+                          * Color space conversion (the JPEG image will use the
+                            same color space as the input image)
+                          * Color quantization
+                          * DCT/IDCT algorithm selection
+                          * Smoothing
+                          * Downsampling/upsampling
+                          * IDCT scaling
+                          * Partial image decompression
+                          * Transformations using jpegtran
+                        Any switches used to enable or configure those features
+                        will be ignored.
+
         -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
@@ -204,8 +237,9 @@ Switches for advanced users:
                         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.
+                        N MCU blocks (samples in lossless mode) 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
diff --git a/win/jconfig.h.in b/win/jconfig.h.in
deleted file mode 100644 (file)
index 7814731..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#define JPEG_LIB_VERSION  @JPEG_LIB_VERSION@
-#define LIBJPEG_TURBO_VERSION  @VERSION@
-#define LIBJPEG_TURBO_VERSION_NUMBER  @LIBJPEG_TURBO_VERSION_NUMBER@
-#define COLOR_PICKER_ENABLE @COLOR_PICKER_ENABLE@
-
-#cmakedefine C_ARITH_CODING_SUPPORTED
-#cmakedefine D_ARITH_CODING_SUPPORTED
-#cmakedefine MEM_SRCDST_SUPPORTED
-#cmakedefine WITH_SIMD
-
-#define BITS_IN_JSAMPLE  @BITS_IN_JSAMPLE@      /* use 8 or 12 */
-
-#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 */
index fca72b7..650fbe9 100644 (file)
@@ -24,7 +24,7 @@ BEGIN
             VALUE "ProductVersion", "@VERSION@"
             VALUE "ProductName", "@CMAKE_PROJECT_NAME@"
             VALUE "InternalName", "jpeg@SO_MAJOR_VERSION@"
-            VALUE "LegalCopyright", "Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others"
+            VALUE "LegalCopyright", L"Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others"
             VALUE "OriginalFilename", "jpeg@SO_MAJOR_VERSION@.dll"
         END
     END
diff --git a/win/jpeg62-memsrcdst.def b/win/jpeg62-memsrcdst.def
deleted file mode 100644 (file)
index 4d24a14..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-EXPORTS
-  jcopy_block_row @ 1 ;
-  jcopy_sample_rows @ 2 ;
-  jdiv_round_up @ 3 ;
-  jinit_1pass_quantizer @ 4 ;
-  jinit_2pass_quantizer @ 5 ;
-  jinit_c_coef_controller @ 6 ;
-  jinit_c_main_controller @ 7 ;
-  jinit_c_master_control @ 8 ;
-  jinit_c_prep_controller @ 9 ;
-  jinit_color_converter @ 10 ;
-  jinit_color_deconverter @ 11 ;
-  jinit_compress_master @ 12 ;
-  jinit_d_coef_controller @ 13 ;
-  jinit_d_main_controller @ 14 ;
-  jinit_d_post_controller @ 15 ;
-  jinit_downsampler @ 16 ;
-  jinit_forward_dct @ 17 ;
-  jinit_huff_decoder @ 18 ;
-  jinit_huff_encoder @ 19 ;
-  jinit_input_controller @ 20 ;
-  jinit_inverse_dct @ 21 ;
-  jinit_marker_reader @ 22 ;
-  jinit_marker_writer @ 23 ;
-  jinit_master_decompress @ 24 ;
-  jinit_memory_mgr @ 25 ;
-  jinit_merged_upsampler @ 26 ;
-  jinit_phuff_decoder @ 27 ;
-  jinit_phuff_encoder @ 28 ;
-  jinit_upsampler @ 29 ;
-  jpeg_CreateCompress @ 30 ;
-  jpeg_CreateDecompress @ 31 ;
-  jpeg_abort @ 32 ;
-  jpeg_abort_compress @ 33 ;
-  jpeg_abort_decompress @ 34 ;
-  jpeg_add_quant_table @ 35 ;
-  jpeg_alloc_huff_table @ 36 ;
-  jpeg_alloc_quant_table @ 37 ;
-  jpeg_calc_output_dimensions @ 38 ;
-  jpeg_consume_input @ 39 ;
-  jpeg_copy_critical_parameters @ 40 ;
-  jpeg_default_colorspace @ 41 ;
-  jpeg_destroy @ 42 ;
-  jpeg_destroy_compress @ 43 ;
-  jpeg_destroy_decompress @ 44 ;
-  jpeg_fdct_float @ 45 ;
-  jpeg_fdct_ifast @ 46 ;
-  jpeg_fdct_islow @ 47 ;
-  jpeg_fill_bit_buffer @ 48 ;
-  jpeg_finish_compress @ 49 ;
-  jpeg_finish_decompress @ 50 ;
-  jpeg_finish_output @ 51 ;
-  jpeg_free_large @ 52 ;
-  jpeg_free_small @ 53 ;
-  jpeg_gen_optimal_table @ 54 ;
-  jpeg_get_large @ 55 ;
-  jpeg_get_small @ 56 ;
-  jpeg_has_multiple_scans @ 57 ;
-  jpeg_huff_decode @ 58 ;
-  jpeg_idct_1x1 @ 59 ;
-  jpeg_idct_2x2 @ 60 ;
-  jpeg_idct_4x4 @ 61 ;
-  jpeg_idct_float @ 62 ;
-  jpeg_idct_ifast @ 63 ;
-  jpeg_idct_islow @ 64 ;
-  jpeg_input_complete @ 65 ;
-  jpeg_make_c_derived_tbl @ 66 ;
-  jpeg_make_d_derived_tbl @ 67 ;
-  jpeg_mem_available @ 68 ;
-  jpeg_mem_init @ 69 ;
-  jpeg_mem_term @ 70 ;
-  jpeg_new_colormap @ 71 ;
-  jpeg_open_backing_store @ 72 ;
-  jpeg_quality_scaling @ 73 ;
-  jpeg_read_coefficients @ 74 ;
-  jpeg_read_header @ 75 ;
-  jpeg_read_raw_data @ 76 ;
-  jpeg_read_scanlines @ 77 ;
-  jpeg_resync_to_restart @ 78 ;
-  jpeg_save_markers @ 79 ;
-  jpeg_set_colorspace @ 80 ;
-  jpeg_set_defaults @ 81 ;
-  jpeg_set_linear_quality @ 82 ;
-  jpeg_set_marker_processor @ 83 ;
-  jpeg_set_quality @ 84 ;
-  jpeg_simple_progression @ 85 ;
-  jpeg_start_compress @ 86 ;
-  jpeg_start_decompress @ 87 ;
-  jpeg_start_output @ 88 ;
-  jpeg_std_error @ 89 ;
-  jpeg_stdio_dest @ 90 ;
-  jpeg_stdio_src @ 91 ;
-  jpeg_suppress_tables @ 92 ;
-  jpeg_write_coefficients @ 93 ;
-  jpeg_write_m_byte @ 94 ;
-  jpeg_write_m_header @ 95 ;
-  jpeg_write_marker @ 96 ;
-  jpeg_write_raw_data @ 97 ;
-  jpeg_write_scanlines @ 98 ;
-  jpeg_write_tables @ 99 ;
-  jround_up @ 100 ;
-  jzero_far @ 101 ;
-  jpeg_mem_dest @ 102 ;
-  jpeg_mem_src @ 103 ;
-  jpeg_skip_scanlines @ 104 ;
-  jpeg_crop_scanline @ 105 ;
-  jpeg_read_icc_profile @ 106 ;
-  jpeg_write_icc_profile @ 107 ;
index f3c69b2..cded425 100644 (file)
@@ -100,7 +100,34 @@ EXPORTS
   jpeg_write_tables @ 99 ;
   jround_up @ 100 ;
   jzero_far @ 101 ;
-  jpeg_skip_scanlines @ 102 ;
-  jpeg_crop_scanline @ 103 ;
-  jpeg_read_icc_profile @ 104 ;
-  jpeg_write_icc_profile @ 105 ;
+  jpeg_mem_dest @ 102 ;
+  jpeg_mem_src @ 103 ;
+  jpeg_skip_scanlines @ 104 ;
+  jpeg_crop_scanline @ 105 ;
+  jpeg_read_icc_profile @ 106 ;
+  jpeg_write_icc_profile @ 107 ;
+  j12copy_sample_rows @ 108 ;
+  j12init_1pass_quantizer @ 109 ;
+  j12init_2pass_quantizer @ 110 ;
+  j12init_c_coef_controller @ 111 ;
+  j12init_c_main_controller @ 112 ;
+  j12init_c_prep_controller @ 113 ;
+  j12init_color_converter @ 114 ;
+  j12init_color_deconverter @ 115 ;
+  j12init_d_coef_controller @ 116 ;
+  j12init_d_main_controller @ 117 ;
+  j12init_d_post_controller @ 118 ;
+  j12init_downsampler @ 119 ;
+  j12init_forward_dct @ 120 ;
+  j12init_inverse_dct @ 121 ;
+  j12init_merged_upsampler @ 122 ;
+  j12init_upsampler @ 123 ;
+  jpeg12_read_raw_data @ 124 ;
+  jpeg12_read_scanlines @ 125 ;
+  jpeg12_write_raw_data @ 126 ;
+  jpeg12_write_scanlines @ 127 ;
+  jpeg12_skip_scanlines @ 128 ;
+  jpeg12_crop_scanline @ 129 ;
+  jpeg_enable_lossless @ 130 ;
+  jpeg16_read_scanlines @ 131 ;
+  jpeg16_write_scanlines @ 132 ;
diff --git a/win/jpeg7-memsrcdst.def b/win/jpeg7-memsrcdst.def
deleted file mode 100644 (file)
index a005aff..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-EXPORTS
-  jcopy_block_row @ 1 ;
-  jcopy_sample_rows @ 2 ;
-  jdiv_round_up @ 3 ;
-  jinit_1pass_quantizer @ 4 ;
-  jinit_2pass_quantizer @ 5 ;
-  jinit_c_coef_controller @ 6 ;
-  jinit_c_main_controller @ 7 ;
-  jinit_c_master_control @ 8 ;
-  jinit_c_prep_controller @ 9 ;
-  jinit_color_converter @ 10 ;
-  jinit_color_deconverter @ 11 ;
-  jinit_compress_master @ 12 ;
-  jinit_d_coef_controller @ 13 ;
-  jinit_d_main_controller @ 14 ;
-  jinit_d_post_controller @ 15 ;
-  jinit_downsampler @ 16 ;
-  jinit_forward_dct @ 17 ;
-  jinit_huff_decoder @ 18 ;
-  jinit_huff_encoder @ 19 ;
-  jinit_input_controller @ 20 ;
-  jinit_inverse_dct @ 21 ;
-  jinit_marker_reader @ 22 ;
-  jinit_marker_writer @ 23 ;
-  jinit_master_decompress @ 24 ;
-  jinit_memory_mgr @ 25 ;
-  jinit_merged_upsampler @ 26 ;
-  jinit_phuff_decoder @ 27 ;
-  jinit_phuff_encoder @ 28 ;
-  jinit_upsampler @ 29 ;
-  jpeg_CreateCompress @ 30 ;
-  jpeg_CreateDecompress @ 31 ;
-  jpeg_abort @ 32 ;
-  jpeg_abort_compress @ 33 ;
-  jpeg_abort_decompress @ 34 ;
-  jpeg_add_quant_table @ 35 ;
-  jpeg_alloc_huff_table @ 36 ;
-  jpeg_alloc_quant_table @ 37 ;
-  jpeg_calc_jpeg_dimensions @ 38 ;
-  jpeg_calc_output_dimensions @ 39 ;
-  jpeg_consume_input @ 40 ;
-  jpeg_copy_critical_parameters @ 41 ;
-  jpeg_default_colorspace @ 42 ;
-  jpeg_default_qtables @ 43 ;
-  jpeg_destroy @ 44 ;
-  jpeg_destroy_compress @ 45 ;
-  jpeg_destroy_decompress @ 46 ;
-  jpeg_fdct_float @ 47 ;
-  jpeg_fdct_ifast @ 48 ;
-  jpeg_fdct_islow @ 49 ;
-  jpeg_fill_bit_buffer @ 50 ;
-  jpeg_finish_compress @ 51 ;
-  jpeg_finish_decompress @ 52 ;
-  jpeg_finish_output @ 53 ;
-  jpeg_free_large @ 54 ;
-  jpeg_free_small @ 55 ;
-  jpeg_gen_optimal_table @ 56 ;
-  jpeg_get_large @ 57 ;
-  jpeg_get_small @ 58 ;
-  jpeg_has_multiple_scans @ 59 ;
-  jpeg_huff_decode @ 60 ;
-  jpeg_idct_1x1 @ 61 ;
-  jpeg_idct_2x2 @ 62 ;
-  jpeg_idct_4x4 @ 63 ;
-  jpeg_idct_float @ 64 ;
-  jpeg_idct_ifast @ 65 ;
-  jpeg_idct_islow @ 66 ;
-  jpeg_input_complete @ 67 ;
-  jpeg_make_c_derived_tbl @ 68 ;
-  jpeg_make_d_derived_tbl @ 69 ;
-  jpeg_mem_available @ 70 ;
-  jpeg_mem_init @ 71 ;
-  jpeg_mem_term @ 72 ;
-  jpeg_new_colormap @ 73 ;
-  jpeg_open_backing_store @ 74 ;
-  jpeg_quality_scaling @ 75 ;
-  jpeg_read_coefficients @ 76 ;
-  jpeg_read_header @ 77 ;
-  jpeg_read_raw_data @ 78 ;
-  jpeg_read_scanlines @ 79 ;
-  jpeg_resync_to_restart @ 80 ;
-  jpeg_save_markers @ 81 ;
-  jpeg_set_colorspace @ 82 ;
-  jpeg_set_defaults @ 83 ;
-  jpeg_set_linear_quality @ 84 ;
-  jpeg_set_marker_processor @ 85 ;
-  jpeg_set_quality @ 86 ;
-  jpeg_simple_progression @ 87 ;
-  jpeg_start_compress @ 88 ;
-  jpeg_start_decompress @ 89 ;
-  jpeg_start_output @ 90 ;
-  jpeg_std_error @ 91 ;
-  jpeg_stdio_dest @ 92 ;
-  jpeg_stdio_src @ 93 ;
-  jpeg_suppress_tables @ 94 ;
-  jpeg_write_coefficients @ 95 ;
-  jpeg_write_m_byte @ 96 ;
-  jpeg_write_m_header @ 97 ;
-  jpeg_write_marker @ 98 ;
-  jpeg_write_raw_data @ 99 ;
-  jpeg_write_scanlines @ 100 ;
-  jpeg_write_tables @ 101 ;
-  jround_up @ 102 ;
-  jzero_far @ 103 ;
-  jpeg_mem_dest @ 104 ;
-  jpeg_mem_src @ 105 ;
-  jpeg_skip_scanlines @ 106 ;
-  jpeg_crop_scanline @ 107 ;
-  jpeg_read_icc_profile @ 108 ;
-  jpeg_write_icc_profile @ 109 ;
index 49f4c02..ba7f442 100644 (file)
@@ -102,7 +102,34 @@ EXPORTS
   jpeg_write_tables @ 101 ;
   jround_up @ 102 ;
   jzero_far @ 103 ;
-  jpeg_skip_scanlines @ 104 ;
-  jpeg_crop_scanline @ 105 ;
-  jpeg_read_icc_profile @ 106 ;
-  jpeg_write_icc_profile @ 107 ;
+  jpeg_mem_dest @ 104 ;
+  jpeg_mem_src @ 105 ;
+  jpeg_skip_scanlines @ 106 ;
+  jpeg_crop_scanline @ 107 ;
+  jpeg_read_icc_profile @ 108 ;
+  jpeg_write_icc_profile @ 109 ;
+  j12copy_sample_rows @ 110 ;
+  j12init_1pass_quantizer @ 111 ;
+  j12init_2pass_quantizer @ 112 ;
+  j12init_c_coef_controller @ 113 ;
+  j12init_c_main_controller @ 114 ;
+  j12init_c_prep_controller @ 115 ;
+  j12init_color_converter @ 116 ;
+  j12init_color_deconverter @ 117 ;
+  j12init_d_coef_controller @ 118 ;
+  j12init_d_main_controller @ 119 ;
+  j12init_d_post_controller @ 120 ;
+  j12init_downsampler @ 121 ;
+  j12init_forward_dct @ 122 ;
+  j12init_inverse_dct @ 123 ;
+  j12init_merged_upsampler @ 124 ;
+  j12init_upsampler @ 125 ;
+  jpeg12_read_raw_data @ 126 ;
+  jpeg12_read_scanlines @ 127 ;
+  jpeg12_write_raw_data @ 128 ;
+  jpeg12_write_scanlines @ 129 ;
+  jpeg12_skip_scanlines @ 130 ;
+  jpeg12_crop_scanline @ 131 ;
+  jpeg_enable_lossless @ 132 ;
+  jpeg16_read_scanlines @ 133 ;
+  jpeg16_write_scanlines @ 134 ;
index 0a53125..9fa1fe6 100644 (file)
@@ -109,3 +109,28 @@ EXPORTS
   jpeg_crop_scanline @ 108 ;
   jpeg_read_icc_profile @ 109 ;
   jpeg_write_icc_profile @ 110 ;
+  j12copy_sample_rows @ 111 ;
+  j12init_1pass_quantizer @ 112 ;
+  j12init_2pass_quantizer @ 113 ;
+  j12init_c_coef_controller @ 114 ;
+  j12init_c_main_controller @ 115 ;
+  j12init_c_prep_controller @ 116 ;
+  j12init_color_converter @ 117 ;
+  j12init_color_deconverter @ 118 ;
+  j12init_d_coef_controller @ 119 ;
+  j12init_d_main_controller @ 120 ;
+  j12init_d_post_controller @ 121 ;
+  j12init_downsampler @ 122 ;
+  j12init_forward_dct @ 123 ;
+  j12init_inverse_dct @ 124 ;
+  j12init_merged_upsampler @ 125 ;
+  j12init_upsampler @ 126 ;
+  jpeg12_read_raw_data @ 127 ;
+  jpeg12_read_scanlines @ 128 ;
+  jpeg12_write_raw_data @ 129 ;
+  jpeg12_write_scanlines @ 130 ;
+  jpeg12_skip_scanlines @ 131 ;
+  jpeg12_crop_scanline @ 132 ;
+  jpeg_enable_lossless @ 133 ;
+  jpeg16_read_scanlines @ 134 ;
+  jpeg16_write_scanlines @ 135 ;
index cc7ab3a..c6cfc2d 100644 (file)
@@ -24,7 +24,7 @@ BEGIN
             VALUE "ProductVersion", "@VERSION@"
             VALUE "ProductName", "@CMAKE_PROJECT_NAME@"
             VALUE "InternalName", "turbojpeg"
-            VALUE "LegalCopyright", "Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others"
+            VALUE "LegalCopyright", L"Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others"
             VALUE "OriginalFilename", "turbojpeg.dll"
         END
     END
index c57fe38..a62fc1a 100644 (file)
@@ -116,23 +116,23 @@ 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:
+of progression parameters.  You can create multiple-scan sequential or lossless
+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.
+the components to be included in the scan, and for progressive and lossless
+JPEG it also specifies the progression/lossless 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
+followed by a colon (':') and the four progressive/lossless-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
@@ -143,13 +143,32 @@ The progression parameters for each scan are:
         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 lossless parameters for each scan are:
+        Ss      Predictor selection value
+        Se      Must be zero
+        Ah      Must be zero
+        Al      Point transform value
+
+If the progression/lossless 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.)
+Ss and Se values other than 0 and 63 appear.  cjpeg also automatically
+determines whether the script represents a lossless file, by observing whether
+Ss (the predictor selection value) is non-zero and Se is zero, which are
+illegal values for progressive and sequential files.  (The -progressive and
+-lossless switches are not needed to specify this; in fact, they are 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
diff --git a/wrbmp.c b/wrbmp.c
index 45fff68..7850e7b 100644 (file)
--- a/wrbmp.c
+++ b/wrbmp.c
@@ -480,6 +480,9 @@ jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2,
   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/wrgif.c
index 620a3ba..2377357 100644 (file)
--- a/wrgif.c
+++ b/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 @@ put_3bytes(gif_dest_ptr dinfo, int val)
 
 
 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 @@ emit_header(gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
       }
     } 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 @@ start_output_gif(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
   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 @@ put_LZW_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
                    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 @@ put_raw_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
                    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 @@ calc_buffer_dimensions_gif(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  */
 
 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 @@ jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw)
     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 @@ jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw)
   return (djpeg_dest_ptr)dest;
 }
 
-#endif /* GIF_SUPPORTED */
+#endif /* defined(GIF_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/wrppm.c b/wrppm.c
index 57c8aaf..b4f9897 100644 (file)
--- a/wrppm.c
+++ b/wrppm.c
@@ -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))
 
 
 /*
@@ -58,7 +59,7 @@
 
 
 /*
- * 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 +71,9 @@ typedef struct {
 
   /* 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 +108,12 @@ copy_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
 {
   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 +135,14 @@ put_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, JDIMENSION rows_supplied)
 {
   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,13 +164,13 @@ put_cmyk(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
 {
   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++;
+    _JSAMPLE r, g, b, c = *ptr++, m = *ptr++, y = *ptr++, k = *ptr++;
     cmyk_to_rgb(c, m, y, k, &r, &g, &b);
     PUTPPMSAMPLE(bufferptr, r);
     PUTPPMSAMPLE(bufferptr, g);
@@ -191,13 +192,13 @@ put_demapped_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
   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 +216,11 @@ put_demapped_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
 {
   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 +305,13 @@ calc_buffer_dimensions_ppm(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
  */
 
 GLOBAL(djpeg_dest_ptr)
-jinit_write_ppm(j_decompress_ptr cinfo)
+_jinit_write_ppm(j_decompress_ptr cinfo)
 {
   ppm_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 = (ppm_dest_ptr)
       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -325,7 +329,7 @@ jinit_write_ppm(j_decompress_ptr cinfo)
     ((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 +340,7 @@ jinit_write_ppm(j_decompress_ptr cinfo)
      * 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 +357,9 @@ jinit_write_ppm(j_decompress_ptr cinfo)
       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 +367,5 @@ jinit_write_ppm(j_decompress_ptr cinfo)
   return (djpeg_dest_ptr)dest;
 }
 
-#endif /* PPM_SUPPORTED */
+#endif /* defined(PPM_SUPPORTED) &&
+          (BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)) */
index 67ca1f0..110e421 100644 (file)
--- a/wrtarga.c
+++ b/wrtarga.c
@@ -230,6 +230,9 @@ jinit_write_targa(j_decompress_ptr cinfo)
 {
   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,