Merge branch '1.4.x'
diff --git a/BUILDING.txt b/BUILDING.txt
index a3ec49d..32a9936 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -84,14 +84,10 @@
 for 64-bit build instructions.)
 
   cd {source_directory}
-  autoreconf -fiv
   cd {build_directory}
   sh {source_directory}/configure [additional configure flags]
   make
 
-NOTE: Running autoreconf in the source directory is usually only necessary if
-building libjpeg-turbo from the SVN repository.
-
 This will generate the following files under .libs/
 
   libjpeg.a
@@ -425,12 +421,6 @@
 Once built, lipo can be used to combine the ARMv6, v7, v7s, and/or v8 variants
 into a universal library.
 
-NOTE: If you are building libjpeg-turbo from the "official" project tarball,
-then it is highly likely that you will need to run 'autoreconf -fiv' in the
-source tree prior to building ARMv7, v7s, or v8 iOS binaries using the
-techniques described above.  Otherwise, you may get a libtool error such as
-"unable to infer tagged configuration."
-
 
 Building libjpeg-turbo for Android
 ----------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bd91493..df874e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,7 +9,7 @@
 endif()
 
 project(libjpeg-turbo C)
-set(VERSION 1.4.2)
+set(VERSION 1.4.80)
 
 if(CYGWIN OR NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
   execute_process(COMMAND "date" "+%Y%m%d" OUTPUT_VARIABLE BUILD)
@@ -356,6 +356,10 @@
   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_STRIP71_132 a5c3706bb2e59bd01786b1181f67f97c)
+  set(MD5_PPM_444_ISLOW_SKIP1_6 ef63901f71ef7a75cd78253fc0914f84)
+  set(MD5_PPM_444_ISLOW_PROG_STRIP13_110 6d228f8d05381d8639f3d078b91b2ee0)
   set(MD5_JPEG_CROP cdb35ff4b4519392690ea040c56ea99c)
 else()
   set(TESTORIG testorig.jpg)
@@ -405,6 +409,13 @@
   set(MD5_BMP_420_ISLOW_565D 6bde71526acc44bcff76f696df8638d2)
   set(MD5_BMP_420M_ISLOW_565 8dc0185245353cfa32ad97027342216f)
   set(MD5_BMP_420M_ISLOW_565D d1be3a3339166255e76fa50a0d70d73e)
+  set(MD5_PPM_420_ISLOW_SKIP15_31 c4c65c1e43d7275cd50328a61e6534f0)
+  set(MD5_PPM_420_ISLOW_ARI_SKIP16_139 087c6b123db16ac00cb88c5b590bb74a)
+  set(MD5_PPM_420_ISLOW_PROG_STRIP71_132 a7f2ba6ea335f03549888bed66a89fae)
+  set(MD5_PPM_420_ISLOW_ARI_STRIP4_56 0e5e44a39b94817917a1bac72903246b)
+  set(MD5_PPM_444_ISLOW_SKIP1_6 5606f86874cf26b8fcee1117a0a436a6)
+  set(MD5_PPM_444_ISLOW_PROG_STRIP13_110 40b5d9742558dca6229d7332fc2dda07)
+  set(MD5_PPM_444_ISLOW_ARI_STRIP0_36 9aceb5b9449c900b892a1d2fe39351b4)
   set(MD5_JPEG_CROP b4197f377e621c4e9b1d20471432610d)
 endif()
 
@@ -653,7 +664,7 @@
         -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
     # CC: YCC->RGB  SAMP: fullsize  FDCT: islow  ENT: prog arith
     add_test(cjpeg${suffix}-444-islow-progari
-      ${dir}cjpeg${suffix} -sample 1x1 -dct int -progressive -arithmetic
+      ${dir}cjpeg${suffix} -sample 1x1 -dct int -prog -arithmetic
         -outfile testout_444_islow_progari.jpg
         ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm)
     add_test(cjpeg${suffix}-444-islow-progari-cmp
@@ -757,6 +768,93 @@
         -DFILE=testout_420m_islow_565D.bmp
         -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
   endif()
+
+  # 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_test(djpeg${suffix}-420-islow-skip15_31
+    ${dir}djpeg${suffix} -dct int -skip 15,31 -ppm
+      -outfile testout_420_islow_skip15,31.ppm
+      ${CMAKE_SOURCE_DIR}/testimages/${TESTORIG})
+  add_test(djpeg${suffix}-420-islow-skip15_31-cmp
+    ${CMAKE_COMMAND} -DMD5=${MD5_PPM_420_ISLOW_SKIP15_31}
+      -DFILE=testout_420_islow_skip15,31.ppm
+      -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: Yes  ENT: arith
+  if(WITH_ARITH_DEC)
+    add_test(djpeg${suffix}-420-islow-ari-skip16_139
+      ${dir}djpeg${suffix} -dct int -skip 16,139 -ppm
+        -outfile testout_420_islow_ari_skip16,139.ppm
+        ${CMAKE_SOURCE_DIR}/testimages/testimgari.jpg)
+    add_test(djpeg${suffix}-420-islow-ari_skip16_139-cmp
+      ${CMAKE_COMMAND} -DMD5=${MD5_PPM_420_ISLOW_ARI_SKIP16_139}
+        -DFILE=testout_420_islow_ari_skip16,139.ppm
+        -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  endif()
+  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: prog huff
+  add_test(cjpeg${suffix}-420-islow-prog
+    ${dir}cjpeg${suffix} -dct int -prog -outfile testout_420_islow_prog.jpg
+      ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm)
+  add_test(djpeg${suffix}-420-islow-prog-strip71_132
+    ${dir}djpeg${suffix} -dct int -strip 71,132 -ppm
+      -outfile testout_420_islow_strip71,132.ppm testout_420_islow_prog.jpg)
+  add_test(djpeg${suffix}-420-islow-prog-strip71_132-cmp
+    ${CMAKE_COMMAND} -DMD5=${MD5_PPM_420_ISLOW_PROG_STRIP71_132}
+      -DFILE=testout_420_islow_strip71,132.ppm
+      -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  # Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: arith
+  if(WITH_ARITH_DEC)
+    add_test(djpeg${suffix}-420-islow-ari-strip4_56
+      ${dir}djpeg${suffix} -dct int -strip 4,56 -ppm
+        -outfile testout_420_islow_ari_strip4,56.ppm
+        ${CMAKE_SOURCE_DIR}/testimages/testimgari.jpg)
+    add_test(djpeg${suffix}-420-islow-ari-strip4_56-cmp
+      ${CMAKE_COMMAND} -DMD5=${MD5_PPM_420_ISLOW_ARI_STRIP4_56}
+        -DFILE=testout_420_islow_ari_strip4,56.ppm
+        -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  endif()
+  # Context rows: No   Intra-iMCU row: Yes  ENT: huff
+  add_test(cjpeg${suffix}-444-islow
+    ${dir}cjpeg${suffix} -dct int -sample 1x1 -outfile testout_444_islow.jpg
+      ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm)
+  add_test(djpeg${suffix}-444-islow-skip1_6
+    ${dir}djpeg${suffix} -dct int -skip 1,6 -ppm
+      -outfile testout_444_islow_skip1,6.ppm testout_444_islow.jpg)
+  add_test(djpeg${suffix}-444-islow-skip1_6-cmp
+    ${CMAKE_COMMAND} -DMD5=${MD5_PPM_444_ISLOW_SKIP1_6}
+      -DFILE=testout_444_islow_skip1,6.ppm
+      -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  # Context rows: No   Intra-iMCU row: No   ENT: prog huff
+  add_test(cjpeg${suffix}-444-islow-prog
+    ${dir}cjpeg${suffix} -dct int -prog -sample 1x1
+      -outfile testout_444_islow_prog.jpg
+      ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm)
+  add_test(djpeg${suffix}-444-islow-prog-strip13_110
+    ${dir}djpeg${suffix} -dct int -strip 13,110 -ppm
+      -outfile testout_444_islow_prog_strip13,110.ppm testout_444_islow_prog.jpg)
+  add_test(djpeg${suffix}-444-islow-prog_strip13_110-cmp
+    ${CMAKE_COMMAND} -DMD5=${MD5_PPM_444_ISLOW_PROG_STRIP13_110}
+      -DFILE=testout_444_islow_prog_strip13,110.ppm
+      -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+  # Context rows: No   Intra-iMCU row: No   ENT: arith
+  if(WITH_ARITH_ENC)
+    add_test(cjpeg${suffix}-444-islow-ari
+      ${dir}cjpeg${suffix} -dct int -arithmetic -sample 1x1
+        -outfile testout_444_islow_ari.jpg
+        ${CMAKE_SOURCE_DIR}/testimages/testorig.ppm)
+    if(WITH_ARITH_DEC)
+      add_test(djpeg${suffix}-444-islow-ari-strip0_36
+        ${dir}djpeg${suffix} -dct int -strip 0,36 -ppm
+          -outfile testout_444_islow_ari_strip0,36.ppm
+          testout_444_islow_ari.jpg)
+      add_test(djpeg${suffix}-444-islow-ari-strip0_36-cmp
+        ${CMAKE_COMMAND} -DMD5=${MD5_PPM_444_ISLOW_ARI_STRIP0_36}
+          -DFILE=testout_444_islow_ari_strip0,36.ppm
+          -P ${CMAKE_SOURCE_DIR}/cmakescripts/md5cmp.cmake)
+    endif()
+  endif()
+
   add_test(jpegtran${suffix}-crop
     ${dir}jpegtran${suffix} -crop 120x90+20+50 -transpose -perfect
       -outfile testout_crop.jpg ${CMAKE_SOURCE_DIR}/testimages/${TESTORIG})
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 3b6b844..5ae9431 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,17 +1,45 @@
-1.4.2
-=====
+1.5 pre-beta
+============
 
-[1] Fixed an issue whereby cjpeg would segfault if a Windows bitmap with a
+[1] Added full SIMD acceleration for PowerPC platforms using AltiVec VMX
+(128-bit SIMD) instructions.  Although the performance of libjpeg-turbo on
+PowerPC was already good, due to the increased number of registers available
+to the compiler vs. x86, it was still possible to speed up compression by about
+3-4x and decompression by about 2-2.5x (relative to libjpeg v6b) through the
+use of AltiVec instructions.
+
+[2] Added a new libjpeg API function (jpeg_skip_scanlines()) that can be used
+to partially decode a JPEG image.  See libjpeg.txt for more details.
+
+[3] The TJCompressor and TJDecompressor classes in the TurboJPEG Java API now
+implement the Closeable interface, so those classes can be used with a
+try-with-resources statement.
+
+[4] The TurboJPEG Java classes now throw unchecked idiomatic exceptions
+(IllegalArgumentException, IllegalStateException) for unrecoverable errors
+caused by incorrect API usage, and those classes throw a new checked exception
+type (TJException) for errors that are passed through from the C library.
+
+[5] Fixed an issue whereby cjpeg would segfault if a Windows bitmap with a
 negative width or height was used as an input image (Windows bitmaps can have
 a negative height if they are stored in top-down order, but such files are
 rare and not supported by libjpeg-turbo.)
 
-[2] Fixed an issue whereby, under certain circumstances, libjpeg-turbo would
+[6] Source buffers for the TurboJPEG C API functions, as well as the
+jpeg_mem_src() function in the libjpeg API, are now declared as const pointers.
+This facilitates passing read-only buffers to those functions and ensures the
+caller that the source buffer will not be modified.  This should not create any
+backward API or ABI incompatibilities with prior libjpeg-turbo releases.
+
+[7] The MIPS DSPr2 SIMD code can now be compiled to support either FR=0 or FR=1
+FPUs.
+
+[8] Fixed an issue whereby, under certain circumstances, libjpeg-turbo would
 incorrectly encode certain JPEG images when quality=100 and the fast integer
 forward DCT were used.  This was known to cause 'make test' to fail when the
 library was built with '-march=haswell' on x86 systems.
 
-[3] Fixed an issue whereby libjpeg-turbo would crash when built with the latest
+[9] Fixed an issue whereby libjpeg-turbo would crash when built with the latest
 & greatest development version of the Clang/LLVM compiler.  This was caused by
 an x86-64 ABI conformance issue in some of libjpeg-turbo's 64-bit SSE2 SIMD
 routines.  Those routines were incorrectly using a 64-bit mov instruction to
@@ -21,15 +49,15 @@
 structure members into a single 64-bit register, and this exposed the ABI
 conformance issue.
 
-[4] Fixed a bug in the MIPS DSPr2 4:2:0 "plain" (non-fancy and non-merged)
+[10] Fixed a bug in the MIPS DSPr2 4:2:0 "plain" (non-fancy and non-merged)
 upsampling routine that caused a buffer overflow (and subsequent segfault) when
 decompressing a 4:2:0 JPEG image whose scaled output width was less than 16
 pixels.  The "plain" upsampling routines are normally only used when
 decompressing a non-YCbCr JPEG image, but they are also used when decompressing
 a JPEG image whose scaled output height is 1.
 
-[5] Fixed various negative left shifts and other issues reported by the GCC and
-Clang undefined behavior sanitizers.  None of these was known to pose a
+[11] Fixed various negative left shifts and other issues reported by the GCC
+and Clang undefined behavior sanitizers.  None of these was known to pose a
 security threat, but removing the warnings makes it easier to detect actual
 security issues, should they arise in the future.
 
diff --git a/Makefile.am b/Makefile.am
index 3a12fde..18bd2d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -168,7 +168,7 @@
 EXTRA_DIST = win release $(DOCS) testimages CMakeLists.txt \
 	sharedlib/CMakeLists.txt cmakescripts libjpeg.map.in doc doxygen.config \
 	doxygen-extra.css jccolext.c jdcolext.c jdcol565.c jdmrgext.c jdmrg565.c \
-	jstdhuff.c LICENSE.txt
+	jstdhuff.c jdcoefct.h jdmainct.h jdsample.h
 
 dist-hook:
 	rm -rf `find $(distdir) -name .svn`
@@ -210,6 +210,10 @@
 MD5_PPM_420M_ISLOW_3_8 = 343d19015531b7bbe746124127244fa8
 MD5_PPM_420M_ISLOW_1_4 = 35fd59d866e44659edfa3c18db2a3edb
 MD5_PPM_420M_ISLOW_1_8 = ccaed48ac0aedefda5d4abe4013f4ad7
+MD5_PPM_420_ISLOW_SKIP15_31 = 86664cd9dc956536409e44e244d20a97
+MD5_PPM_420_ISLOW_PROG_STRIP71_132 = a5c3706bb2e59bd01786b1181f67f97c
+MD5_PPM_444_ISLOW_SKIP1_6 = ef63901f71ef7a75cd78253fc0914f84
+MD5_PPM_444_ISLOW_PROG_STRIP13_110 = 6d228f8d05381d8639f3d078b91b2ee0
 MD5_JPEG_CROP = cdb35ff4b4519392690ea040c56ea99c
 
 else
@@ -262,6 +266,13 @@
 MD5_BMP_420_ISLOW_565D = 6bde71526acc44bcff76f696df8638d2
 MD5_BMP_420M_ISLOW_565 = 8dc0185245353cfa32ad97027342216f
 MD5_BMP_420M_ISLOW_565D =d1be3a3339166255e76fa50a0d70d73e
+MD5_PPM_420_ISLOW_SKIP15_31 = c4c65c1e43d7275cd50328a61e6534f0
+MD5_PPM_420_ISLOW_ARI_SKIP16_139 = 087c6b123db16ac00cb88c5b590bb74a
+MD5_PPM_420_ISLOW_PROG_STRIP71_132 = a7f2ba6ea335f03549888bed66a89fae
+MD5_PPM_420_ISLOW_ARI_STRIP4_56 = 0e5e44a39b94817917a1bac72903246b
+MD5_PPM_444_ISLOW_SKIP1_6 = 5606f86874cf26b8fcee1117a0a436a6
+MD5_PPM_444_ISLOW_PROG_STRIP13_110 = 40b5d9742558dca6229d7332fc2dda07
+MD5_PPM_444_ISLOW_ARI_STRIP0_36 = 9aceb5b9449c900b892a1d2fe39351b4
 MD5_JPEG_CROP = b4197f377e621c4e9b1d20471432610d
 
 endif
@@ -487,7 +498,7 @@
 	md5/md5cmp $(MD5_JPEG_420_ISLOW_ARI) testout_420_islow_ari.jpg
 	rm testout_420_islow_ari.jpg
 # CC: YCC->RGB  SAMP: fullsize  FDCT: islow  ENT: prog arith
-	./cjpeg -sample 1x1 -dct int -progressive -arithmetic -outfile testout_444_islow_progari.jpg $(srcdir)/testimages/testorig.ppm
+	./cjpeg -sample 1x1 -dct int -prog -arithmetic -outfile testout_444_islow_progari.jpg $(srcdir)/testimages/testorig.ppm
 	md5/md5cmp $(MD5_JPEG_444_ISLOW_PROGARI) testout_444_islow_progari.jpg
 	rm testout_444_islow_progari.jpg
 endif
@@ -573,6 +584,51 @@
 	rm testout_420m_islow_565D.bmp
 endif
 
+# 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
+	./djpeg -dct int -skip 15,31 -ppm -outfile testout_420_islow_skip15,31.ppm $(srcdir)/testimages/$(TESTORIG)
+	md5/md5cmp $(MD5_PPM_420_ISLOW_SKIP15_31) testout_420_islow_skip15,31.ppm
+	rm testout_420_islow_skip15,31.ppm
+# Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: Yes  ENT: arith
+if WITH_ARITH_DEC
+	./djpeg -dct int -skip 16,139 -ppm -outfile testout_420_islow_ari_skip16,139.ppm $(srcdir)/testimages/testimgari.jpg
+	md5/md5cmp $(MD5_PPM_420_ISLOW_ARI_SKIP16_139) testout_420_islow_ari_skip16,139.ppm
+	rm testout_420_islow_ari_skip16,139.ppm
+endif
+# Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: prog huff
+	./cjpeg -dct int -prog -outfile testout_420_islow_prog.jpg $(srcdir)/testimages/testorig.ppm
+	./djpeg -dct int -strip 71,132 -ppm -outfile testout_420_islow_prog_strip71,132.ppm testout_420_islow_prog.jpg
+	md5/md5cmp $(MD5_PPM_420_ISLOW_PROG_STRIP71_132) testout_420_islow_prog_strip71,132.ppm
+	rm testout_420_islow_prog_strip71,132.ppm testout_420_islow_prog.jpg
+# Context rows: Yes  Intra-iMCU row: No   iMCU row prefetch: No   ENT: arith
+if WITH_ARITH_DEC
+	./djpeg -dct int -strip 4,56 -ppm -outfile testout_420_islow_ari_strip4,56.ppm $(srcdir)/testimages/testimgari.jpg
+	md5/md5cmp $(MD5_PPM_420_ISLOW_ARI_STRIP4_56) testout_420_islow_ari_strip4,56.ppm
+	rm testout_420_islow_ari_strip4,56.ppm
+endif
+# Context rows: No   Intra-iMCU row: Yes  ENT: huff
+	./cjpeg -dct int -sample 1x1 -outfile testout_444_islow.jpg $(srcdir)/testimages/testorig.ppm
+	./djpeg -dct int -skip 1,6 -ppm -outfile testout_444_islow_skip1,6.ppm testout_444_islow.jpg
+	md5/md5cmp $(MD5_PPM_444_ISLOW_SKIP1_6) testout_444_islow_skip1,6.ppm
+	rm testout_444_islow_skip1,6.ppm testout_444_islow.jpg
+# Context rows: No   Intra-iMCU row: No   ENT: prog huff
+	./cjpeg -dct int -prog -sample 1x1 -outfile testout_444_islow_prog.jpg $(srcdir)/testimages/testorig.ppm
+	./djpeg -dct int -strip 13,110 -ppm -outfile testout_444_islow_prog_strip13,110.ppm testout_444_islow_prog.jpg
+	md5/md5cmp $(MD5_PPM_444_ISLOW_PROG_STRIP13_110) testout_444_islow_prog_strip13,110.ppm
+	rm testout_444_islow_prog_strip13,110.ppm testout_444_islow_prog.jpg
+# Context rows: No   Intra-iMCU row: No   ENT: arith
+if WITH_ARITH_ENC
+	./cjpeg -dct int -arithmetic -sample 1x1 -outfile testout_444_islow_ari.jpg $(srcdir)/testimages/testorig.ppm
+if WITH_ARITH_DEC
+	./djpeg -dct int -strip 0,36 -ppm -outfile testout_444_islow_ari_strip0,36.ppm testout_444_islow_ari.jpg
+	md5/md5cmp $(MD5_PPM_444_ISLOW_ARI_STRIP0_36) testout_444_islow_ari_strip0,36.ppm
+	rm testout_444_islow_ari_strip0,36.ppm
+endif
+	rm testout_444_islow_ari.jpg
+endif
+
 	./jpegtran -crop 120x90+20+50 -transpose -perfect -outfile testout_crop.jpg $(srcdir)/testimages/$(TESTORIG)
 	md5/md5cmp $(MD5_JPEG_CROP) testout_crop.jpg
 	rm testout_crop.jpg
diff --git a/README-turbo.txt b/README-turbo.txt
index 28b6c4d..d81a9c4 100755
--- a/README-turbo.txt
+++ b/README-turbo.txt
@@ -3,12 +3,12 @@
 *******************************************************************************
 
 libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
-NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64,
-and ARM systems.  On such systems, libjpeg-turbo is generally 2-4x as fast as
-libjpeg, all else being equal.  On other types of systems, libjpeg-turbo can
-still outperform libjpeg by a significant amount, by virtue of its
-highly-optimized Huffman coding routines.  In many cases, the performance of
-libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
+NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
+x86, x86-64, ARM, and PowerPC systems.  On such systems, libjpeg-turbo is
+generally 2-4x as fast as libjpeg, all else being equal.  On other types of
+systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by
+virtue of its highly-optimized Huffman coding routines.  In many cases, the
+performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
 
 libjpeg-turbo implements both the traditional libjpeg API as well as the less
 powerful but more straightforward TurboJPEG API.  libjpeg-turbo also features
diff --git a/configure.ac b/configure.ac
index 6a55474..97ed115 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.56])
-AC_INIT([libjpeg-turbo], [1.4.2])
+AC_INIT([libjpeg-turbo], [1.4.80])
 
 AM_INIT_AUTOMAKE([-Wall foreign dist-bzip2])
 AC_PREFIX_DEFAULT(/opt/libjpeg-turbo)
@@ -192,7 +192,7 @@
 RPM_CONFIG_ARGS=
 
 # Memory source/destination managers
-SO_AGE=0
+SO_AGE=1
 MEM_SRCDST_FUNCTIONS=
 if test "x${with_jpeg8}" != "xyes"; then
   AC_MSG_CHECKING([whether to include in-memory source/destination managers])
@@ -203,7 +203,7 @@
     AC_MSG_RESULT(yes)
     AC_DEFINE([MEM_SRCDST_SUPPORTED], [1],
       [Support in-memory source/destination managers])
-    SO_AGE=1
+    SO_AGE=2
     MEM_SRCDST_FUNCTIONS="global:  jpeg_mem_dest;  jpeg_mem_src;";
   else
     AC_MSG_RESULT(no)
@@ -498,6 +498,10 @@
         fi
       fi
       ;;
+    powerpc*)
+      AC_MSG_RESULT([yes (powerpc)])
+      simd_arch=powerpc
+      ;;
     *)
       AC_MSG_RESULT([no ("$host_cpu")])
       with_simd=no;
@@ -523,6 +527,7 @@
 AM_CONDITIONAL([SIMD_ARM], [test "x$simd_arch" = "xarm"])
 AM_CONDITIONAL([SIMD_ARM_64], [test "x$simd_arch" = "xaarch64"])
 AM_CONDITIONAL([SIMD_MIPS], [test "x$simd_arch" = "xmips"])
+AM_CONDITIONAL([SIMD_POWERPC], [test "x$simd_arch" = "xpowerpc"])
 AM_CONDITIONAL([X86_64], [test "x$host_cpu" = "xx86_64" -o "x$host_cpu" = "xamd64"])
 AM_CONDITIONAL([WITH_TURBOJPEG], [test "x$with_turbojpeg" != "xno"])
 
diff --git a/djpeg.1 b/djpeg.1
index 73d0514..17296ab 100644
--- a/djpeg.1
+++ b/djpeg.1
@@ -1,4 +1,4 @@
-.TH DJPEG 1 "21 November 2014"
+.TH DJPEG 1 "26 June 2015"
 .SH NAME
 djpeg \- decompress a JPEG file to an image file
 .SH SYNOPSIS
@@ -194,6 +194,16 @@
 Load input file into memory before decompressing.  This feature was implemented
 mainly as a way of testing the in-memory source manager (jpeg_mem_src().)
 .TP
+.BI \-skip " Y0,Y1"
+Decode all rows of the JPEG image except those between Y0 and Y1 (inclusive.)
+Note that if decompression scaling is being used, Y0 and Y1 are relative to the
+scaled image dimensions.
+.TP
+.BI \-strip " Y0,Y1"
+Decode only the rows of the JPEG image between Y0 and Y1 (inclusive.)  Note
+that if decompression scaling is being used, Y0 and Y1 are relative to the
+scaled image dimensions.
+.TP
 .B \-verbose
 Enable debug printout.  More
 .BR \-v 's
diff --git a/djpeg.c b/djpeg.c
index 8ddff96..d41f94f 100644
--- a/djpeg.c
+++ b/djpeg.c
@@ -4,7 +4,8 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010-2011, 2013-2014, D. R. Commander.
+ * Copyright (C) 2010-2011, 2013-2015, D. R. Commander.
+ * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains a command-line user interface for the JPEG decompressor.
@@ -88,6 +89,8 @@
 static const char * progname;   /* program name for error messages */
 static char * outfilename;      /* for -outfile switch */
 boolean memsrc;  /* for -memsrc switch */
+boolean strip, skip;
+JDIMENSION startY, endY;
 #define INPUT_BUF_SIZE  4096
 
 
@@ -164,6 +167,8 @@
   fprintf(stderr, "  -memsrc        Load input file into memory before decompressing\n");
 #endif
 
+  fprintf(stderr, "  -skip Y0,Y1    Decode all rows except those between Y0 and Y1 (inclusive)\n");
+  fprintf(stderr, "  -strip Y0,Y1   Decode only rows between Y0 and Y1 (inclusive)\n");
   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
   fprintf(stderr, "  -version       Print version information and exit\n");
   exit(EXIT_FAILURE);
@@ -189,6 +194,8 @@
   requested_fmt = DEFAULT_FMT;  /* set default output file format */
   outfilename = NULL;
   memsrc = FALSE;
+  strip = FALSE;
+  skip = FALSE;
   cinfo->err->trace_level = 0;
 
   /* Scan command line options, adjust parameters */
@@ -361,7 +368,7 @@
       /* RLE output format. */
       requested_fmt = FMT_RLE;
 
-    } else if (keymatch(arg, "scale", 1)) {
+    } else if (keymatch(arg, "scale", 2)) {
       /* Scale the output image by a fraction M/N. */
       if (++argn >= argc)       /* advance to next argument */
         usage();
@@ -369,6 +376,21 @@
                  &cinfo->scale_num, &cinfo->scale_denom) != 2)
         usage();
 
+    } else if (keymatch(arg, "strip", 2)) {
+      if (++argn >= argc)
+        usage();
+      if (sscanf(argv[argn], "%d,%d", &startY, &endY) != 2 || startY > endY)
+        usage();
+      strip = TRUE;
+
+
+    } else if (keymatch(arg, "skip", 2)) {
+      if (++argn >= argc)
+        usage();
+      if (sscanf(argv[argn], "%d,%d", &startY, &endY) != 2 || startY > endY)
+        usage();
+      skip = TRUE;
+
     } else if (keymatch(arg, "targa", 1)) {
       /* Targa output format. */
       requested_fmt = FMT_TARGA;
@@ -634,14 +656,64 @@
   /* Start decompressor */
   (void) jpeg_start_decompress(&cinfo);
 
-  /* Write output file header */
-  (*dest_mgr->start_output) (&cinfo, dest_mgr);
+  /* Strip decode */
+  if (strip || skip) {
+    JDIMENSION tmp;
 
-  /* 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);
+    /* Check for valid endY.  We cannot check this value until after
+     * jpeg_start_decompress() is called.  Note that we have already verified
+     * that startY <= endY.
+     */
+    if (endY > cinfo.output_height - 1) {
+      fprintf(stderr, "%s: strip %d-%d exceeds image height %d\n", progname,
+              startY, endY, cinfo.output_height);
+      exit(EXIT_FAILURE);
+    }
+
+    /* Write output file header.  This is a hack to ensure that the destination
+     * manager creates an image of the proper size for the partial decode.
+     */
+    tmp = cinfo.output_height;
+    cinfo.output_height = endY - startY + 1;
+    if (skip)
+      cinfo.output_height = tmp - cinfo.output_height;
+    (*dest_mgr->start_output) (&cinfo, dest_mgr);
+    cinfo.output_height = tmp;
+
+    /* Process data */
+    if (skip) {
+      while (cinfo.output_scanline < startY) {
+        num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+                                            dest_mgr->buffer_height);
+        (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+      }
+      jpeg_skip_scanlines(&cinfo, endY - startY + 1);
+      while (cinfo.output_scanline < cinfo.output_height) {
+        num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+                                            dest_mgr->buffer_height);
+        (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+      }
+    } else {
+      jpeg_skip_scanlines(&cinfo, startY);
+      while (cinfo.output_scanline <= endY) {
+        num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+                                            dest_mgr->buffer_height);
+        (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+      }
+      jpeg_skip_scanlines(&cinfo, cinfo.output_height - endY + 1);
+    }
+
+  /* Normal full image decode */
+  } else {
+    /* Write output file header */
+    (*dest_mgr->start_output) (&cinfo, dest_mgr);
+
+    /* Process data */
+    while (cinfo.output_scanline < cinfo.output_height) {
+      num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+                                          dest_mgr->buffer_height);
+      (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+    }
   }
 
 #ifdef PROGRESS_REPORT
diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html
index 233fe6c..553ec92 100644
--- a/doc/html/group___turbo_j_p_e_g.html
+++ b/doc/html/group___turbo_j_p_e_g.html
@@ -132,10 +132,10 @@
 <tr class="memdesc:ga0f6dbd18adf38b7d46ac547f0f4d562c"><td class="mdescLeft">&#160;</td><td class="mdescRight">The number of transform operations.  <a href="#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#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to return an error if the transform is not perfect.  <a href="#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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to return an error if the transform is not perfect.  <a href="#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#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to discard any partial MCU blocks that cannot be transformed.  <a href="#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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to discard any partial MCU blocks that cannot be transformed.  <a href="#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="#ga9c771a757fc1294add611906b89ab2d2">More...</a><br/></td></tr>
@@ -144,7 +144,7 @@
 <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="#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#gae403193ceb4aafb7e0f56ab587b48616" 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="#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#gad02cd42b69f193a0623a9c801788df3a" 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="#gafbf992bbf6e006705886333703ffab31">More...</a><br/></td></tr>
 <tr class="separator:gafbf992bbf6e006705886333703ffab31"><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="#ga0aba955473315e405295d978f0c16511">More...</a><br/></td></tr>
@@ -218,7 +218,7 @@
 <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#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" 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="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>
@@ -226,15 +226,15 @@
 <tr class="memitem:ga3d10c47fbe4a2489a2b30c931551d01a"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3d10c47fbe4a2489a2b30c931551d01a">tjInitCompress</a> (void)</td></tr>
 <tr class="memdesc:ga3d10c47fbe4a2489a2b30c931551d01a"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG compressor instance.  <a href="#ga3d10c47fbe4a2489a2b30c931551d01a">More...</a><br/></td></tr>
 <tr class="separator:ga3d10c47fbe4a2489a2b30c931551d01a"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaba62b7a98f960839b588579898495cf2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2">tjCompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:gaba62b7a98f960839b588579898495cf2"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an RGB, grayscale, or CMYK image into a JPEG image.  <a href="#gaba62b7a98f960839b588579898495cf2">More...</a><br/></td></tr>
-<tr class="separator:gaba62b7a98f960839b588579898495cf2"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67">tjCompressFromYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a YUV planar image into a JPEG image.  <a href="#ga0b931126c7a615ddc3bbd0cca6698d67">More...</a><br/></td></tr>
-<tr class="separator:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaa89a1982cb4556b12ae7af4439991af6"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa89a1982cb4556b12ae7af4439991af6">tjCompressFromYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char **srcPlanes, int width, int *strides, int height, int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)</td></tr>
-<tr class="memdesc:gaa89a1982cb4556b12ae7af4439991af6"><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="#gaa89a1982cb4556b12ae7af4439991af6">More...</a><br/></td></tr>
-<tr class="separator:gaa89a1982cb4556b12ae7af4439991af6"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaf38f2ed44bdc88e730e08b632fa6e88e"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e">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:gaf38f2ed44bdc88e730e08b632fa6e88e"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress an RGB, grayscale, or CMYK image into a JPEG image.  <a href="#gaf38f2ed44bdc88e730e08b632fa6e88e">More...</a><br/></td></tr>
+<tr class="separator:gaf38f2ed44bdc88e730e08b632fa6e88e"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga6f6de375d6ec0020faba627e37e5a060"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6f6de375d6ec0020faba627e37e5a060">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:ga6f6de375d6ec0020faba627e37e5a060"><td class="mdescLeft">&#160;</td><td class="mdescRight">Compress a YUV planar image into a JPEG image.  <a href="#ga6f6de375d6ec0020faba627e37e5a060">More...</a><br/></td></tr>
+<tr class="separator:ga6f6de375d6ec0020faba627e37e5a060"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga0b84c682d8accf097d7a743c965d3464"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0b84c682d8accf097d7a743c965d3464">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:ga0b84c682d8accf097d7a743c965d3464"><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="#ga0b84c682d8accf097d7a743c965d3464">More...</a><br/></td></tr>
+<tr class="separator:ga0b84c682d8accf097d7a743c965d3464"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b">tjBufSize</a> (int width, int height, int jpegSubsamp)</td></tr>
 <tr class="memdesc:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><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="#gaccc5bca7f12fcdcc302e6e1c6d4b311b">More...</a><br/></td></tr>
 <tr class="separator:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -250,42 +250,42 @@
 <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="#ga1a209696c6a80748f20e134b3c64789f">More...</a><br/></td></tr>
 <tr class="separator:ga1a209696c6a80748f20e134b3c64789f"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga0a5ffbf7cb58a5b6a8201114fe889360"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0a5ffbf7cb58a5b6a8201114fe889360">tjEncodeYUV3</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:ga0a5ffbf7cb58a5b6a8201114fe889360"><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an RGB or grayscale image into a YUV planar image.  <a href="#ga0a5ffbf7cb58a5b6a8201114fe889360">More...</a><br/></td></tr>
-<tr class="separator:ga0a5ffbf7cb58a5b6a8201114fe889360"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gaa791db8598853ddcad24e42897ef1269"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaa791db8598853ddcad24e42897ef1269">tjEncodeYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:gaa791db8598853ddcad24e42897ef1269"><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="#gaa791db8598853ddcad24e42897ef1269">More...</a><br/></td></tr>
-<tr class="separator:gaa791db8598853ddcad24e42897ef1269"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaabe05acd734990053ad1294b5ef239aa"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaabe05acd734990053ad1294b5ef239aa">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:gaabe05acd734990053ad1294b5ef239aa"><td class="mdescLeft">&#160;</td><td class="mdescRight">Encode an RGB or grayscale image into a YUV planar image.  <a href="#gaabe05acd734990053ad1294b5ef239aa">More...</a><br/></td></tr>
+<tr class="separator:gaabe05acd734990053ad1294b5ef239aa"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga8a65ed3bd12df57c219d46afbc9008f1"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga8a65ed3bd12df57c219d46afbc9008f1">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:ga8a65ed3bd12df57c219d46afbc9008f1"><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="#ga8a65ed3bd12df57c219d46afbc9008f1">More...</a><br/></td></tr>
+<tr class="separator:ga8a65ed3bd12df57c219d46afbc9008f1"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:gae5408179d041e2a2f7199c8283cf649e"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae5408179d041e2a2f7199c8283cf649e">tjInitDecompress</a> (void)</td></tr>
 <tr class="memdesc:gae5408179d041e2a2f7199c8283cf649e"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a TurboJPEG decompressor instance.  <a href="#gae5408179d041e2a2f7199c8283cf649e">More...</a><br/></td></tr>
 <tr class="separator:gae5408179d041e2a2f7199c8283cf649e"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gacd0fac3af74b3511d39b4781b7103086"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gacd0fac3af74b3511d39b4781b7103086">tjDecompressHeader3</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, int *jpegSubsamp, int *jpegColorspace)</td></tr>
-<tr class="memdesc:gacd0fac3af74b3511d39b4781b7103086"><td class="mdescLeft">&#160;</td><td class="mdescRight">Retrieve information about a JPEG image without decompressing it.  <a href="#gacd0fac3af74b3511d39b4781b7103086">More...</a><br/></td></tr>
-<tr class="separator:gacd0fac3af74b3511d39b4781b7103086"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga3fced455e504e8ff4fbad28ba94a3020"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3fced455e504e8ff4fbad28ba94a3020">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:ga3fced455e504e8ff4fbad28ba94a3020"><td class="mdescLeft">&#160;</td><td class="mdescRight">Retrieve information about a JPEG image without decompressing it.  <a href="#ga3fced455e504e8ff4fbad28ba94a3020">More...</a><br/></td></tr>
+<tr class="separator:ga3fced455e504e8ff4fbad28ba94a3020"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga6449044b9af402999ccf52f401333be8"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="structtjscalingfactor.html">tjscalingfactor</a> *DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6449044b9af402999ccf52f401333be8">tjGetScalingFactors</a> (int *numscalingfactors)</td></tr>
 <tr class="memdesc:ga6449044b9af402999ccf52f401333be8"><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="#ga6449044b9af402999ccf52f401333be8">More...</a><br/></td></tr>
 <tr class="separator:ga6449044b9af402999ccf52f401333be8"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gada69cc6443d1bb493b40f1626259e5e9"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gada69cc6443d1bb493b40f1626259e5e9">tjDecompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:gada69cc6443d1bb493b40f1626259e5e9"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to an RGB, grayscale, or CMYK image.  <a href="#gada69cc6443d1bb493b40f1626259e5e9">More...</a><br/></td></tr>
-<tr class="separator:gada69cc6443d1bb493b40f1626259e5e9"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga7c08b340ad7f8e85d407bd9e81d44d07"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga7c08b340ad7f8e85d407bd9e81d44d07">tjDecompressToYUV2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pad, int height, int flags)</td></tr>
-<tr class="memdesc:ga7c08b340ad7f8e85d407bd9e81d44d07"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to a YUV planar image.  <a href="#ga7c08b340ad7f8e85d407bd9e81d44d07">More...</a><br/></td></tr>
-<tr class="separator:ga7c08b340ad7f8e85d407bd9e81d44d07"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga0828a38ae29631ac28b6857cefb0eebf"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0828a38ae29631ac28b6857cefb0eebf">tjDecompressToYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes, int width, int *strides, int height, int flags)</td></tr>
-<tr class="memdesc:ga0828a38ae29631ac28b6857cefb0eebf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image planes.  <a href="#ga0828a38ae29631ac28b6857cefb0eebf">More...</a><br/></td></tr>
-<tr class="separator:ga0828a38ae29631ac28b6857cefb0eebf"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga132ae2c2cadcf64c8bb0f3bdf69da3ed"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga132ae2c2cadcf64c8bb0f3bdf69da3ed">tjDecodeYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:ga132ae2c2cadcf64c8bb0f3bdf69da3ed"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decode a YUV planar image into an RGB or grayscale image.  <a href="#ga132ae2c2cadcf64c8bb0f3bdf69da3ed">More...</a><br/></td></tr>
-<tr class="separator:ga132ae2c2cadcf64c8bb0f3bdf69da3ed"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:ga6cb5b0e1101a2b20edea576e11faf93d"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga6cb5b0e1101a2b20edea576e11faf93d">tjDecodeYUVPlanes</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags)</td></tr>
-<tr class="memdesc:ga6cb5b0e1101a2b20edea576e11faf93d"><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="#ga6cb5b0e1101a2b20edea576e11faf93d">More...</a><br/></td></tr>
-<tr class="separator:ga6cb5b0e1101a2b20edea576e11faf93d"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gad8026a417e16a76313bc0a6c9e8b2ba2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad8026a417e16a76313bc0a6c9e8b2ba2">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:gad8026a417e16a76313bc0a6c9e8b2ba2"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to an RGB, grayscale, or CMYK image.  <a href="#gad8026a417e16a76313bc0a6c9e8b2ba2">More...</a><br/></td></tr>
+<tr class="separator:gad8026a417e16a76313bc0a6c9e8b2ba2"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga39e08906528db5a764670ea48d344b09"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga39e08906528db5a764670ea48d344b09">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:ga39e08906528db5a764670ea48d344b09"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image to a YUV planar image.  <a href="#ga39e08906528db5a764670ea48d344b09">More...</a><br/></td></tr>
+<tr class="separator:ga39e08906528db5a764670ea48d344b09"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga38d0ef90692663b3ffb5b16da2541512"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga38d0ef90692663b3ffb5b16da2541512">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:ga38d0ef90692663b3ffb5b16da2541512"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image planes.  <a href="#ga38d0ef90692663b3ffb5b16da2541512">More...</a><br/></td></tr>
+<tr class="separator:ga38d0ef90692663b3ffb5b16da2541512"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:ga077c61027b875afecd5a1613bf18b3c1"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga077c61027b875afecd5a1613bf18b3c1">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:ga077c61027b875afecd5a1613bf18b3c1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Decode a YUV planar image into an RGB or grayscale image.  <a href="#ga077c61027b875afecd5a1613bf18b3c1">More...</a><br/></td></tr>
+<tr class="separator:ga077c61027b875afecd5a1613bf18b3c1"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gaf42f19b7a496eb18bdc84fe61ee6d3e2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaf42f19b7a496eb18bdc84fe61ee6d3e2">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:gaf42f19b7a496eb18bdc84fe61ee6d3e2"><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="#gaf42f19b7a496eb18bdc84fe61ee6d3e2">More...</a><br/></td></tr>
+<tr class="separator:gaf42f19b7a496eb18bdc84fe61ee6d3e2"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga3155b775bfbac9dbba869b95a0367902"><td class="memItemLeft" align="right" valign="top">DLLEXPORT <a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3155b775bfbac9dbba869b95a0367902">tjInitTransform</a> (void)</td></tr>
 <tr class="memdesc:ga3155b775bfbac9dbba869b95a0367902"><td class="mdescLeft">&#160;</td><td class="mdescRight">Create a new TurboJPEG transformer instance.  <a href="#ga3155b775bfbac9dbba869b95a0367902">More...</a><br/></td></tr>
 <tr class="separator:ga3155b775bfbac9dbba869b95a0367902"><td class="memSeparator" colspan="2">&#160;</td></tr>
-<tr class="memitem:gae403193ceb4aafb7e0f56ab587b48616"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616">tjTransform</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, 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:gae403193ceb4aafb7e0f56ab587b48616"><td class="mdescLeft">&#160;</td><td class="mdescRight">Losslessly transform a JPEG image into another JPEG image.  <a href="#gae403193ceb4aafb7e0f56ab587b48616">More...</a><br/></td></tr>
-<tr class="separator:gae403193ceb4aafb7e0f56ab587b48616"><td class="memSeparator" colspan="2">&#160;</td></tr>
+<tr class="memitem:gad02cd42b69f193a0623a9c801788df3a"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a">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:gad02cd42b69f193a0623a9c801788df3a"><td class="mdescLeft">&#160;</td><td class="mdescRight">Losslessly transform a JPEG image into another JPEG image.  <a href="#gad02cd42b69f193a0623a9c801788df3a">More...</a><br/></td></tr>
+<tr class="separator:gad02cd42b69f193a0623a9c801788df3a"><td class="memSeparator" colspan="2">&#160;</td></tr>
 <tr class="memitem:ga674adee917b95ad4a896f1ba39e12540"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga674adee917b95ad4a896f1ba39e12540">tjDestroy</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle)</td></tr>
 <tr class="memdesc:ga674adee917b95ad4a896f1ba39e12540"><td class="mdescLeft">&#160;</td><td class="mdescRight">Destroy a TurboJPEG compressor, decompressor, or transformer instance.  <a href="#ga674adee917b95ad4a896f1ba39e12540">More...</a><br/></td></tr>
 <tr class="separator:ga674adee917b95ad4a896f1ba39e12540"><td class="memSeparator" colspan="2">&#160;</td></tr>
@@ -455,7 +455,7 @@
 </div><div class="memdoc">
 
 <p>Disable buffer (re)allocation. </p>
-<p>If passed to <a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> or <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>, 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>If passed to <a class="el" href="group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> or <a class="el" href="group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>, 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>
 
 </div>
 </div>
@@ -517,7 +517,7 @@
 </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#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> for more information. </p>
 
 </div>
 </div>
@@ -545,7 +545,7 @@
       </table>
 </div><div class="memdoc">
 
-<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" 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>
 
 </div>
 </div>
@@ -559,7 +559,7 @@
       </table>
 </div><div class="memdoc">
 
-<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</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>
@@ -574,7 +574,7 @@
       </table>
 </div><div class="memdoc">
 
-<p>This option will cause <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> to discard any partial MCU blocks that cannot be transformed. </p>
 
 </div>
 </div>
@@ -761,7 +761,7 @@
       </table>
 </div><div class="memdoc">
 
-<p>Transform operations for <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" 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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> </p>
 <table class="fieldtable">
 <tr><th colspan="2">Enumerator</th></tr><tr><td class="fieldname"><em><a class="anchor" id="gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27"></a>TJXOP_NONE</em>&nbsp;</td><td class="fielddoc">
 <p>Do not transform the position of the image pixels. </p>
@@ -812,7 +812,7 @@
 </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 <a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> 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>You should always use this function to allocate the JPEG destination buffer(s) for <a class="el" href="group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> and <a class="el" href="group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> 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>
 <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>
@@ -918,7 +918,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gaba62b7a98f960839b588579898495cf2"></a>
+<a class="anchor" id="gaf38f2ed44bdc88e730e08b632fa6e88e"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -931,7 +931,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>srcBuf</em>, </td>
         </tr>
         <tr>
@@ -1000,7 +1000,7 @@
 <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. This buffer is not modified.</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">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">height</td><td>height (in pixels) of the source image</td></tr>
@@ -1022,7 +1022,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga0b931126c7a615ddc3bbd0cca6698d67"></a>
+<a class="anchor" id="ga6f6de375d6ec0020faba627e37e5a060"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1035,7 +1035,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>srcBuf</em>, </td>
         </tr>
         <tr>
@@ -1098,7 +1098,7 @@
 <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#gaf451664a62c1f6c7cc5a6401f32908c9" 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>.) This buffer is not modified.</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#gaf451664a62c1f6c7cc5a6401f32908c9" 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>
@@ -1119,7 +1119,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gaa89a1982cb4556b12ae7af4439991af6"></a>
+<a class="anchor" id="ga0b84c682d8accf097d7a743c965d3464"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1132,7 +1132,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramtype">const unsigned char **&#160;</td>
           <td class="paramname"><em>srcPlanes</em>, </td>
         </tr>
         <tr>
@@ -1144,7 +1144,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
+          <td class="paramtype">const int *&#160;</td>
           <td class="paramname"><em>strides</em>, </td>
         </tr>
         <tr>
@@ -1195,7 +1195,7 @@
 <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#ga6f98d977bfa9d167c97172e876ba61e2" 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. These image planes are not modified.</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#ga6f98d977bfa9d167c97172e876ba61e2" 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>
@@ -1216,7 +1216,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga132ae2c2cadcf64c8bb0f3bdf69da3ed"></a>
+<a class="anchor" id="ga077c61027b875afecd5a1613bf18b3c1"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1229,7 +1229,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>srcBuf</em>, </td>
         </tr>
         <tr>
@@ -1293,7 +1293,7 @@
 <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#gaf451664a62c1f6c7cc5a6401f32908c9" 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>.) This buffer is not modified.</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#gaf451664a62c1f6c7cc5a6401f32908c9" 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>
@@ -1309,7 +1309,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga6cb5b0e1101a2b20edea576e11faf93d"></a>
+<a class="anchor" id="gaf42f19b7a496eb18bdc84fe61ee6d3e2"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1322,13 +1322,13 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramtype">const unsigned char **&#160;</td>
           <td class="paramname"><em>srcPlanes</em>, </td>
         </tr>
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">int *&#160;</td>
+          <td class="paramtype">const int *&#160;</td>
           <td class="paramname"><em>strides</em>, </td>
         </tr>
         <tr>
@@ -1386,7 +1386,7 @@
 <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#ga6f98d977bfa9d167c97172e876ba61e2" 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. These image planes are not modified.</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#ga6f98d977bfa9d167c97172e876ba61e2" 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>
@@ -1402,7 +1402,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gada69cc6443d1bb493b40f1626259e5e9"></a>
+<a class="anchor" id="gad8026a417e16a76313bc0a6c9e8b2ba2"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1415,7 +1415,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
@@ -1472,7 +1472,7 @@
 <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. This buffer is not modified.</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 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#ga6449044b9af402999ccf52f401333be8" 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>
@@ -1487,7 +1487,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gacd0fac3af74b3511d39b4781b7103086"></a>
+<a class="anchor" id="ga3fced455e504e8ff4fbad28ba94a3020"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1500,7 +1500,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
@@ -1545,7 +1545,7 @@
 <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. This buffer is not modified.</td></tr>
+    <tr><td class="paramname">jpegBuf</td><td>pointer to a buffer containing a JPEG image</td></tr>
     <tr><td class="paramname">jpegSize</td><td>size of the JPEG image (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</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</td></tr>
@@ -1558,7 +1558,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga7c08b340ad7f8e85d407bd9e81d44d07"></a>
+<a class="anchor" id="ga39e08906528db5a764670ea48d344b09"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1571,7 +1571,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
@@ -1623,7 +1623,7 @@
 <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. This buffer is not modified.</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#gaf451664a62c1f6c7cc5a6401f32908c9" 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>
@@ -1637,7 +1637,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga0828a38ae29631ac28b6857cefb0eebf"></a>
+<a class="anchor" id="ga38d0ef90692663b3ffb5b16da2541512"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1650,7 +1650,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
@@ -1702,7 +1702,7 @@
 <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. This buffer is not modified.</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">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#ga6f98d977bfa9d167c97172e876ba61e2" 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>
@@ -1741,7 +1741,7 @@
 
 </div>
 </div>
-<a class="anchor" id="ga0a5ffbf7cb58a5b6a8201114fe889360"></a>
+<a class="anchor" id="gaabe05acd734990053ad1294b5ef239aa"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1754,7 +1754,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>srcBuf</em>, </td>
         </tr>
         <tr>
@@ -1818,7 +1818,7 @@
 <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. This buffer is not modified.</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">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">height</td><td>height (in pixels) of the source image</td></tr>
@@ -1834,7 +1834,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gaa791db8598853ddcad24e42897ef1269"></a>
+<a class="anchor" id="ga8a65ed3bd12df57c219d46afbc9008f1"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -1847,7 +1847,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>srcBuf</em>, </td>
         </tr>
         <tr>
@@ -1911,7 +1911,7 @@
 <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. This buffer is not modified.</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">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">height</td><td>height (in pixels) of the source image</td></tr>
@@ -1942,7 +1942,7 @@
 </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 <a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> or <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> or that were manually allocated using <a class="el" href="group___turbo_j_p_e_g.html#ga5c9234bda6d993cdaffdd89bf81a00ff" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a>.</p>
+<p>You should always use this function to free JPEG destination buffer(s) that were automatically (re)allocated by <a class="el" href="group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e" title="Compress an RGB, grayscale, or CMYK image into a JPEG image.">tjCompress2()</a> or <a class="el" href="group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> or that were manually allocated using <a class="el" href="group___turbo_j_p_e_g.html#ga5c9234bda6d993cdaffdd89bf81a00ff" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</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</td></tr>
@@ -2199,7 +2199,7 @@
 
 </div>
 </div>
-<a class="anchor" id="gae403193ceb4aafb7e0f56ab587b48616"></a>
+<a class="anchor" id="gad02cd42b69f193a0623a9c801788df3a"></a>
 <div class="memitem">
 <div class="memproto">
       <table class="memname">
@@ -2212,7 +2212,7 @@
         <tr>
           <td class="paramkey"></td>
           <td></td>
-          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramtype">const unsigned char *&#160;</td>
           <td class="paramname"><em>jpegBuf</em>, </td>
         </tr>
         <tr>
@@ -2264,7 +2264,7 @@
 <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. This buffer is not modified.</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">
diff --git a/doc/html/search/all_74.js b/doc/html/search/all_74.js
index 5b46106..444aaef 100644
--- a/doc/html/search/all_74.js
+++ b/doc/html/search/all_74.js
@@ -8,24 +8,24 @@
   ['tjblueoffset',['tjBlueOffset',['../group___turbo_j_p_e_g.html#ga84e2e35d3f08025f976ec1ec53693dea',1,'turbojpeg.h']]],
   ['tjbufsize',['tjBufSize',['../group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b',1,'turbojpeg.h']]],
   ['tjbufsizeyuv2',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#gaf451664a62c1f6c7cc5a6401f32908c9',1,'turbojpeg.h']]],
-  ['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2',1,'turbojpeg.h']]],
-  ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67',1,'turbojpeg.h']]],
-  ['tjcompressfromyuvplanes',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#gaa89a1982cb4556b12ae7af4439991af6',1,'turbojpeg.h']]],
+  ['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e',1,'turbojpeg.h']]],
+  ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga6f6de375d6ec0020faba627e37e5a060',1,'turbojpeg.h']]],
+  ['tjcompressfromyuvplanes',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#ga0b84c682d8accf097d7a743c965d3464',1,'turbojpeg.h']]],
   ['tjcs',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
   ['tjcs_5fcmyk',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
   ['tjcs_5fgray',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
   ['tjcs_5frgb',['TJCS_RGB',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a677cb7ccb85c4038ac41964a2e09e555',1,'turbojpeg.h']]],
   ['tjcs_5fycbcr',['TJCS_YCbCr',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a7389b8f65bb387ffedce3efd0d78ec75',1,'turbojpeg.h']]],
   ['tjcs_5fycck',['TJCS_YCCK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a53839e0fe867b76b58d16b0a1a7c598e',1,'turbojpeg.h']]],
-  ['tjdecodeyuv',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga132ae2c2cadcf64c8bb0f3bdf69da3ed',1,'turbojpeg.h']]],
-  ['tjdecodeyuvplanes',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga6cb5b0e1101a2b20edea576e11faf93d',1,'turbojpeg.h']]],
-  ['tjdecompress2',['tjDecompress2',['../group___turbo_j_p_e_g.html#gada69cc6443d1bb493b40f1626259e5e9',1,'turbojpeg.h']]],
-  ['tjdecompressheader3',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#gacd0fac3af74b3511d39b4781b7103086',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuv2',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga7c08b340ad7f8e85d407bd9e81d44d07',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuvplanes',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#ga0828a38ae29631ac28b6857cefb0eebf',1,'turbojpeg.h']]],
+  ['tjdecodeyuv',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga077c61027b875afecd5a1613bf18b3c1',1,'turbojpeg.h']]],
+  ['tjdecodeyuvplanes',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#gaf42f19b7a496eb18bdc84fe61ee6d3e2',1,'turbojpeg.h']]],
+  ['tjdecompress2',['tjDecompress2',['../group___turbo_j_p_e_g.html#gad8026a417e16a76313bc0a6c9e8b2ba2',1,'turbojpeg.h']]],
+  ['tjdecompressheader3',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#ga3fced455e504e8ff4fbad28ba94a3020',1,'turbojpeg.h']]],
+  ['tjdecompresstoyuv2',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga39e08906528db5a764670ea48d344b09',1,'turbojpeg.h']]],
+  ['tjdecompresstoyuvplanes',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#ga38d0ef90692663b3ffb5b16da2541512',1,'turbojpeg.h']]],
   ['tjdestroy',['tjDestroy',['../group___turbo_j_p_e_g.html#ga674adee917b95ad4a896f1ba39e12540',1,'turbojpeg.h']]],
-  ['tjencodeyuv3',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#ga0a5ffbf7cb58a5b6a8201114fe889360',1,'turbojpeg.h']]],
-  ['tjencodeyuvplanes',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#gaa791db8598853ddcad24e42897ef1269',1,'turbojpeg.h']]],
+  ['tjencodeyuv3',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#gaabe05acd734990053ad1294b5ef239aa',1,'turbojpeg.h']]],
+  ['tjencodeyuvplanes',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga8a65ed3bd12df57c219d46afbc9008f1',1,'turbojpeg.h']]],
   ['tjflag_5faccuratedct',['TJFLAG_ACCURATEDCT',['../group___turbo_j_p_e_g.html#gacb233cfd722d66d1ccbf48a7de81f0e0',1,'turbojpeg.h']]],
   ['tjflag_5fbottomup',['TJFLAG_BOTTOMUP',['../group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec',1,'turbojpeg.h']]],
   ['tjflag_5ffastdct',['TJFLAG_FASTDCT',['../group___turbo_j_p_e_g.html#gaabce235db80d3f698b27f36cbd453da2',1,'turbojpeg.h']]],
@@ -70,7 +70,7 @@
   ['tjsamp_5fgray',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
   ['tjscaled',['TJSCALED',['../group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df',1,'turbojpeg.h']]],
   ['tjscalingfactor',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
-  ['tjtransform',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616',1,'tjTransform(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags):&#160;turbojpeg.h'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform():&#160;turbojpeg.h']]],
+  ['tjtransform',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a',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'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform():&#160;turbojpeg.h']]],
   ['tjxop',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]],
   ['tjxop_5fhflip',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
   ['tjxop_5fnone',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
diff --git a/doc/html/search/functions_74.js b/doc/html/search/functions_74.js
index 73b7ee9..69410b0 100644
--- a/doc/html/search/functions_74.js
+++ b/doc/html/search/functions_74.js
@@ -3,18 +3,18 @@
   ['tjalloc',['tjAlloc',['../group___turbo_j_p_e_g.html#ga5c9234bda6d993cdaffdd89bf81a00ff',1,'turbojpeg.h']]],
   ['tjbufsize',['tjBufSize',['../group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b',1,'turbojpeg.h']]],
   ['tjbufsizeyuv2',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#gaf451664a62c1f6c7cc5a6401f32908c9',1,'turbojpeg.h']]],
-  ['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2',1,'turbojpeg.h']]],
-  ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67',1,'turbojpeg.h']]],
-  ['tjcompressfromyuvplanes',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#gaa89a1982cb4556b12ae7af4439991af6',1,'turbojpeg.h']]],
-  ['tjdecodeyuv',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga132ae2c2cadcf64c8bb0f3bdf69da3ed',1,'turbojpeg.h']]],
-  ['tjdecodeyuvplanes',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga6cb5b0e1101a2b20edea576e11faf93d',1,'turbojpeg.h']]],
-  ['tjdecompress2',['tjDecompress2',['../group___turbo_j_p_e_g.html#gada69cc6443d1bb493b40f1626259e5e9',1,'turbojpeg.h']]],
-  ['tjdecompressheader3',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#gacd0fac3af74b3511d39b4781b7103086',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuv2',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga7c08b340ad7f8e85d407bd9e81d44d07',1,'turbojpeg.h']]],
-  ['tjdecompresstoyuvplanes',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#ga0828a38ae29631ac28b6857cefb0eebf',1,'turbojpeg.h']]],
+  ['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaf38f2ed44bdc88e730e08b632fa6e88e',1,'turbojpeg.h']]],
+  ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga6f6de375d6ec0020faba627e37e5a060',1,'turbojpeg.h']]],
+  ['tjcompressfromyuvplanes',['tjCompressFromYUVPlanes',['../group___turbo_j_p_e_g.html#ga0b84c682d8accf097d7a743c965d3464',1,'turbojpeg.h']]],
+  ['tjdecodeyuv',['tjDecodeYUV',['../group___turbo_j_p_e_g.html#ga077c61027b875afecd5a1613bf18b3c1',1,'turbojpeg.h']]],
+  ['tjdecodeyuvplanes',['tjDecodeYUVPlanes',['../group___turbo_j_p_e_g.html#gaf42f19b7a496eb18bdc84fe61ee6d3e2',1,'turbojpeg.h']]],
+  ['tjdecompress2',['tjDecompress2',['../group___turbo_j_p_e_g.html#gad8026a417e16a76313bc0a6c9e8b2ba2',1,'turbojpeg.h']]],
+  ['tjdecompressheader3',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#ga3fced455e504e8ff4fbad28ba94a3020',1,'turbojpeg.h']]],
+  ['tjdecompresstoyuv2',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga39e08906528db5a764670ea48d344b09',1,'turbojpeg.h']]],
+  ['tjdecompresstoyuvplanes',['tjDecompressToYUVPlanes',['../group___turbo_j_p_e_g.html#ga38d0ef90692663b3ffb5b16da2541512',1,'turbojpeg.h']]],
   ['tjdestroy',['tjDestroy',['../group___turbo_j_p_e_g.html#ga674adee917b95ad4a896f1ba39e12540',1,'turbojpeg.h']]],
-  ['tjencodeyuv3',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#ga0a5ffbf7cb58a5b6a8201114fe889360',1,'turbojpeg.h']]],
-  ['tjencodeyuvplanes',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#gaa791db8598853ddcad24e42897ef1269',1,'turbojpeg.h']]],
+  ['tjencodeyuv3',['tjEncodeYUV3',['../group___turbo_j_p_e_g.html#gaabe05acd734990053ad1294b5ef239aa',1,'turbojpeg.h']]],
+  ['tjencodeyuvplanes',['tjEncodeYUVPlanes',['../group___turbo_j_p_e_g.html#ga8a65ed3bd12df57c219d46afbc9008f1',1,'turbojpeg.h']]],
   ['tjfree',['tjFree',['../group___turbo_j_p_e_g.html#ga8c4a1231dc06a450514c835f6471f137',1,'turbojpeg.h']]],
   ['tjgeterrorstr',['tjGetErrorStr',['../group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf',1,'turbojpeg.h']]],
   ['tjgetscalingfactors',['tjGetScalingFactors',['../group___turbo_j_p_e_g.html#ga6449044b9af402999ccf52f401333be8',1,'turbojpeg.h']]],
@@ -24,5 +24,5 @@
   ['tjplaneheight',['tjPlaneHeight',['../group___turbo_j_p_e_g.html#ga1a209696c6a80748f20e134b3c64789f',1,'turbojpeg.h']]],
   ['tjplanesizeyuv',['tjPlaneSizeYUV',['../group___turbo_j_p_e_g.html#ga6f98d977bfa9d167c97172e876ba61e2',1,'turbojpeg.h']]],
   ['tjplanewidth',['tjPlaneWidth',['../group___turbo_j_p_e_g.html#ga63fb66bb1e36c74008c4634360becbb1',1,'turbojpeg.h']]],
-  ['tjtransform',['tjTransform',['../group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616',1,'turbojpeg.h']]]
+  ['tjtransform',['tjTransform',['../group___turbo_j_p_e_g.html#gad02cd42b69f193a0623a9c801788df3a',1,'turbojpeg.h']]]
 ];
diff --git a/doc/html/structtjtransform.html b/doc/html/structtjtransform.html
index 7a07c2a..3bfd129 100644
--- a/doc/html/structtjtransform.html
+++ b/doc/html/structtjtransform.html
@@ -133,7 +133,7 @@
     <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#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a>.</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#gad02cd42b69f193a0623a9c801788df3a" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</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>
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index f9f9e57..0af8ae1 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -5,6 +5,7 @@
   org/libjpegturbo/turbojpeg/TJCompressor
   org/libjpegturbo/turbojpeg/TJCustomFilter
   org/libjpegturbo/turbojpeg/TJDecompressor
+  org/libjpegturbo/turbojpeg/TJException
   org/libjpegturbo/turbojpeg/TJScalingFactor
   org/libjpegturbo/turbojpeg/TJTransform
   org/libjpegturbo/turbojpeg/TJTransformer
diff --git a/java/Makefile.am b/java/Makefile.am
index 23e3412..475dd3f 100644
--- a/java/Makefile.am
+++ b/java/Makefile.am
@@ -10,6 +10,7 @@
 	org/libjpegturbo/turbojpeg/TJCompressor.java \
 	org/libjpegturbo/turbojpeg/TJCustomFilter.java \
 	org/libjpegturbo/turbojpeg/TJDecompressor.java \
+	org/libjpegturbo/turbojpeg/TJException.java \
 	org/libjpegturbo/turbojpeg/TJScalingFactor.java \
 	org/libjpegturbo/turbojpeg/TJTransform.java \
 	org/libjpegturbo/turbojpeg/TJTransformer.java \
@@ -31,6 +32,7 @@
 	org/libjpegturbo/turbojpeg/TJCompressor.class \
 	org/libjpegturbo/turbojpeg/TJCustomFilter.class \
 	org/libjpegturbo/turbojpeg/TJDecompressor.class \
+	org/libjpegturbo/turbojpeg/TJException.class \
 	org/libjpegturbo/turbojpeg/TJLoader.class \
 	org/libjpegturbo/turbojpeg/TJScalingFactor.class \
 	org/libjpegturbo/turbojpeg/TJTransform.class \
diff --git a/java/TJExample.java b/java/TJExample.java
index 7562114..da09807 100644
--- a/java/TJExample.java
+++ b/java/TJExample.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2012, 2014 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2012, 2014-2015 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:
@@ -351,7 +351,7 @@
   public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
                            Rectangle planeRegion, int componentIndex,
                            int transformIndex, TJTransform transform)
-                           throws Exception {
+                           throws TJException {
     for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) {
       coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
     }
diff --git a/java/doc/allclasses-frame.html b/java/doc/allclasses-frame.html
index 509ea50..fecac06 100644
--- a/java/doc/allclasses-frame.html
+++ b/java/doc/allclasses-frame.html
@@ -13,6 +13,7 @@
 <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>
diff --git a/java/doc/allclasses-noframe.html b/java/doc/allclasses-noframe.html
index 3eac18f..1f7fd3c 100644
--- a/java/doc/allclasses-noframe.html
+++ b/java/doc/allclasses-noframe.html
@@ -13,6 +13,7 @@
 <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/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>
 <li><a href="org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a></li>
 <li><a href="org/libjpegturbo/turbojpeg/TJTransformer.html" title="class in org.libjpegturbo.turbojpeg">TJTransformer</a></li>
diff --git a/java/doc/index-all.html b/java/doc/index-all.html
index 1af78be..a02d9c4 100644
--- a/java/doc/index-all.html
+++ b/java/doc/index-all.html
@@ -821,6 +821,16 @@
  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>
+<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>
+<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>
+<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>
+<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>
+<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>
 <dd>
 <div class="block">Fractional scaling factor</div>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJ.html b/java/doc/org/libjpegturbo/turbojpeg/TJ.html
index f8342f2..ffef657 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJ.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJ.html
@@ -983,16 +983,13 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMCUWidth</h4>
-<pre>public static&nbsp;int&nbsp;getMCUWidth(int&nbsp;subsamp)
-                       throws java.lang.Exception</pre>
+<pre>public static&nbsp;int&nbsp;getMCUWidth(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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ subsampling.</dd></dl>
 </li>
 </ul>
 <a name="getMCUHeight(int)">
@@ -1001,16 +998,13 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getMCUHeight</h4>
-<pre>public static&nbsp;int&nbsp;getMCUHeight(int&nbsp;subsamp)
-                        throws java.lang.Exception</pre>
+<pre>public static&nbsp;int&nbsp;getMCUHeight(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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ subsampling.</dd></dl>
 </li>
 </ul>
 <a name="getPixelSize(int)">
@@ -1019,13 +1013,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getPixelSize</h4>
-<pre>public static&nbsp;int&nbsp;getPixelSize(int&nbsp;pixelFormat)
-                        throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">Returns:</span></dt><dd>the pixel size (in bytes) for the given pixel format.</dd></dl>
 </li>
 </ul>
 <a name="getRedOffset(int)">
@@ -1034,17 +1025,14 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getRedOffset</h4>
-<pre>public static&nbsp;int&nbsp;getRedOffset(int&nbsp;pixelFormat)
-                        throws java.lang.Exception</pre>
+<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
  <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.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">Returns:</span></dt><dd>the red offset for the given pixel format.</dd></dl>
 </li>
 </ul>
 <a name="getGreenOffset(int)">
@@ -1053,17 +1041,14 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getGreenOffset</h4>
-<pre>public static&nbsp;int&nbsp;getGreenOffset(int&nbsp;pixelFormat)
-                          throws java.lang.Exception</pre>
+<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
  <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.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">Returns:</span></dt><dd>the green offset for the given pixel format.</dd></dl>
 </li>
 </ul>
 <a name="getBlueOffset(int)">
@@ -1072,17 +1057,14 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getBlueOffset</h4>
-<pre>public static&nbsp;int&nbsp;getBlueOffset(int&nbsp;pixelFormat)
-                         throws java.lang.Exception</pre>
+<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
  <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.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">Returns:</span></dt><dd>the blue offset for the given pixel format.</dd></dl>
 </li>
 </ul>
 <a name="bufSize(int, int, int)">
@@ -1093,16 +1075,13 @@
 <h4>bufSize</h4>
 <pre>public static&nbsp;int&nbsp;bufSize(int&nbsp;width,
           int&nbsp;height,
-          int&nbsp;jpegSubsamp)
-                   throws java.lang.Exception</pre>
+          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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image with the given width, height, and level of chrominance subsampling.</dd></dl>
 </li>
 </ul>
 <a name="bufSizeYUV(int, int, int, int)">
@@ -1114,17 +1093,14 @@
 <pre>public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
              int&nbsp;pad,
              int&nbsp;height,
-             int&nbsp;subsamp)
-                      throws java.lang.Exception</pre>
+             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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image with the given width, height, and level of chrominance subsampling.</dd></dl>
 </li>
 </ul>
 <a name="bufSizeYUV(int, int, int)">
@@ -1136,11 +1112,8 @@
 <pre>@Deprecated
 public static&nbsp;int&nbsp;bufSizeYUV(int&nbsp;width,
                         int&nbsp;height,
-                        int&nbsp;subsamp)
-                      throws java.lang.Exception</pre>
+                        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>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
 </li>
 </ul>
 <a name="planeSizeYUV(int, int, int, int, int)">
@@ -1153,8 +1126,7 @@
                int&nbsp;width,
                int&nbsp;stride,
                int&nbsp;height,
-               int&nbsp;subsamp)
-                        throws java.lang.Exception</pre>
+               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,
@@ -1163,9 +1135,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image with the given parameters.</dd></dl>
 </li>
 </ul>
 <a name="planeWidth(int, int, int)">
@@ -1176,16 +1146,13 @@
 <h4>planeWidth</h4>
 <pre>public static&nbsp;int&nbsp;planeWidth(int&nbsp;componentID,
              int&nbsp;width,
-             int&nbsp;subsamp)
-                      throws java.lang.Exception</pre>
+             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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">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)">
@@ -1196,16 +1163,13 @@
 <h4>planeHeight</h4>
 <pre>public static&nbsp;int&nbsp;planeHeight(int&nbsp;componentID,
               int&nbsp;height,
-              int&nbsp;subsamp)
-                       throws java.lang.Exception</pre>
+              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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dt><span class="strong">Returns:</span></dt><dd>the plane height of a YUV image plane with the given parameters.</dd></dl>
 </li>
 </ul>
 <a name="getScalingFactors()">
@@ -1214,14 +1178,11 @@
 <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()
-                                           throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ this implementation of TurboJPEG supports.</dd></dl>
 </li>
 </ul>
 </li>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
index b7fa3db..29f12b7 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
@@ -90,10 +90,15 @@
 <div class="description">
 <ul class="blockList">
 <li class="blockList">
+<dl>
+<dt>All Implemented Interfaces:</dt>
+<dd>java.io.Closeable, java.lang.AutoCloseable</dd>
+</dl>
 <hr>
 <br>
 <pre>public class <span class="strong">TJCompressor</span>
-extends java.lang.Object</pre>
+extends java.lang.Object
+implements java.io.Closeable</pre>
 <div class="block">TurboJPEG compressor</div>
 </li>
 </ul>
@@ -376,10 +381,10 @@
 <li class="blockList">
 <h4>TJCompressor</h4>
 <pre>public&nbsp;TJCompressor()
-             throws java.lang.Exception</pre>
+             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.</div>
 <dl><dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<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)">
@@ -395,14 +400,14 @@
             int&nbsp;pitch,
             int&nbsp;height,
             int&nbsp;pixelFormat)
-             throws java.lang.Exception</pre>
+             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>java.lang.Exception</code></dd></dl>
+<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)">
@@ -417,11 +422,11 @@
                        int&nbsp;pitch,
                        int&nbsp;height,
                        int&nbsp;pixelFormat)
-             throws java.lang.Exception</pre>
+             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>java.lang.Exception</code></dd></dl>
+<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(java.awt.image.BufferedImage, int, int, int, int)">
@@ -435,7 +440,7 @@
             int&nbsp;y,
             int&nbsp;width,
             int&nbsp;height)
-             throws java.lang.Exception</pre>
+             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>
@@ -446,7 +451,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 </li>
@@ -470,7 +475,7 @@
                   int&nbsp;pitch,
                   int&nbsp;height,
                   int&nbsp;pixelFormat)
-                    throws java.lang.Exception</pre>
+                    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
@@ -488,7 +493,7 @@
  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>java.lang.Exception</code></dd></dl>
+<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)">
@@ -503,11 +508,11 @@
                              int&nbsp;pitch,
                              int&nbsp;height,
                              int&nbsp;pixelFormat)
-                    throws java.lang.Exception</pre>
+                    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>java.lang.Exception</code></dd></dl>
+<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(java.awt.image.BufferedImage, int, int, int, int)">
@@ -521,7 +526,7 @@
                   int&nbsp;y,
                   int&nbsp;width,
                   int&nbsp;height)
-                    throws java.lang.Exception</pre>
+                    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
@@ -533,7 +538,7 @@
  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>java.lang.Exception</code></dd></dl>
+<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(org.libjpegturbo.turbojpeg.YUVImage)">
@@ -543,13 +548,13 @@
 <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 java.lang.Exception</pre>
+                    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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="setSubsamp(int)">
@@ -558,8 +563,7 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setSubsamp</h4>
-<pre>public&nbsp;void&nbsp;setSubsamp(int&nbsp;newSubsamp)
-                throws java.lang.Exception</pre>
+<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
@@ -577,9 +581,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
 </li>
 </ul>
 <a name="setJPEGQuality(int)">
@@ -588,13 +590,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>setJPEGQuality</h4>
-<pre>public&nbsp;void&nbsp;setJPEGQuality(int&nbsp;quality)
-                    throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ 100 = best)</dd></dl>
 </li>
 </ul>
 <a name="compress(byte[], int)">
@@ -605,7 +604,7 @@
 <h4>compress</h4>
 <pre>public&nbsp;void&nbsp;compress(byte[]&nbsp;dstBuf,
             int&nbsp;flags)
-              throws java.lang.Exception</pre>
+              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
@@ -614,7 +613,7 @@
  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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="compress(int)">
@@ -624,7 +623,7 @@
 <li class="blockList">
 <h4>compress</h4>
 <pre>public&nbsp;byte[]&nbsp;compress(int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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
@@ -632,7 +631,7 @@
 <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="compress(java.awt.image.BufferedImage, byte[], int)">
@@ -645,12 +644,12 @@
 public&nbsp;void&nbsp;compress(java.awt.image.BufferedImage&nbsp;srcImage,
                        byte[]&nbsp;dstBuf,
                        int&nbsp;flags)
-              throws java.lang.Exception</pre>
+              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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="compress(java.awt.image.BufferedImage, int)">
@@ -662,12 +661,12 @@
 <pre>@Deprecated
 public&nbsp;byte[]&nbsp;compress(java.awt.image.BufferedImage&nbsp;srcImage,
                          int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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>java.lang.Exception</code></dd></dl>
+<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(org.libjpegturbo.turbojpeg.YUVImage, int)">
@@ -678,7 +677,7 @@
 <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 java.lang.Exception</pre>
+               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
@@ -689,7 +688,7 @@
  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>java.lang.Exception</code></dd></dl>
+<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(byte[], int)">
@@ -701,10 +700,10 @@
 <pre>@Deprecated
 public&nbsp;void&nbsp;encodeYUV(byte[]&nbsp;dstBuf,
                         int&nbsp;flags)
-               throws java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<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)">
@@ -715,7 +714,7 @@
 <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 java.lang.Exception</pre>
+                   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
@@ -728,7 +727,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<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)">
@@ -739,7 +738,7 @@
 <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 java.lang.Exception</pre>
+                   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
@@ -756,7 +755,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<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)">
@@ -767,10 +766,10 @@
 <h4>encodeYUV</h4>
 <pre>@Deprecated
 public&nbsp;byte[]&nbsp;encodeYUV(int&nbsp;flags)
-                 throws java.lang.Exception</pre>
+                 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>java.lang.Exception</code></dd></dl>
+<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(java.awt.image.BufferedImage, byte[], int)">
@@ -783,12 +782,12 @@
 public&nbsp;void&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
                         byte[]&nbsp;dstBuf,
                         int&nbsp;flags)
-               throws java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<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(java.awt.image.BufferedImage, int)">
@@ -800,12 +799,12 @@
 <pre>@Deprecated
 public&nbsp;byte[]&nbsp;encodeYUV(java.awt.image.BufferedImage&nbsp;srcImage,
                           int&nbsp;flags)
-                 throws java.lang.Exception</pre>
+                 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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="getCompressedSize()">
@@ -828,10 +827,15 @@
 <li class="blockList">
 <h4>close</h4>
 <pre>public&nbsp;void&nbsp;close()
-           throws java.lang.Exception</pre>
+           throws <a href="../../../org/libjpegturbo/turbojpeg/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><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<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>
+<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>
 </li>
 </ul>
 <a name="finalize()">
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
index c2b6e61..6bd6fd2 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
@@ -144,7 +144,7 @@
                 int&nbsp;componentID,
                 int&nbsp;transformID,
                 <a href="../../../org/libjpegturbo/turbojpeg/TJTransform.html" title="class in org.libjpegturbo.turbojpeg">TJTransform</a>&nbsp;transform)
-                  throws java.lang.Exception</pre>
+                  throws <a href="../../../org/libjpegturbo/turbojpeg/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
@@ -165,7 +165,7 @@
  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
  parameters and/or cropping region for this transform</dd>
 <dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 </li>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
index dc1dcbd..a914de9 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
@@ -33,7 +33,7 @@
 <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/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next 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>
@@ -91,13 +91,18 @@
 <ul class="blockList">
 <li class="blockList">
 <dl>
+<dt>All Implemented Interfaces:</dt>
+<dd>java.io.Closeable, java.lang.AutoCloseable</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>
 </dl>
 <hr>
 <br>
 <pre>public class <span class="strong">TJDecompressor</span>
-extends java.lang.Object</pre>
+extends java.lang.Object
+implements java.io.Closeable</pre>
 <div class="block">TurboJPEG decompressor</div>
 </li>
 </ul>
@@ -529,10 +534,10 @@
 <li class="blockList">
 <h4>TJDecompressor</h4>
 <pre>public&nbsp;TJDecompressor()
-               throws java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="TJDecompressor(byte[])">
@@ -542,13 +547,13 @@
 <li class="blockList">
 <h4>TJDecompressor</h4>
 <pre>public&nbsp;TJDecompressor(byte[]&nbsp;jpegImage)
-               throws java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="TJDecompressor(byte[], int)">
@@ -559,13 +564,13 @@
 <h4>TJDecompressor</h4>
 <pre>public&nbsp;TJDecompressor(byte[]&nbsp;jpegImage,
               int&nbsp;imageSize)
-               throws java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="TJDecompressor(org.libjpegturbo.turbojpeg.YUVImage)">
@@ -575,14 +580,14 @@
 <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 java.lang.Exception</pre>
+               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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 </li>
@@ -601,13 +606,13 @@
 <h4>setSourceImage</h4>
 <pre>public&nbsp;void&nbsp;setSourceImage(byte[]&nbsp;jpegImage,
                   int&nbsp;imageSize)
-                    throws java.lang.Exception</pre>
+                    throws <a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></pre>
 <div class="block">Associate the JPEG image of length <code>imageSize</code> bytes stored in
  <code>jpegImage</code> with this decompressor instance.  This image will
  be used as the source image for subsequent decompress operations.</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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="setJPEGImage(byte[], int)">
@@ -619,10 +624,10 @@
 <pre>@Deprecated
 public&nbsp;void&nbsp;setJPEGImage(byte[]&nbsp;jpegImage,
                            int&nbsp;imageSize)
-                  throws java.lang.Exception</pre>
+                  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>java.lang.Exception</code></dd></dl>
+<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(org.libjpegturbo.turbojpeg.YUVImage)">
@@ -631,15 +636,12 @@
 <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 java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ be decoded.  This image is not modified.</dd></dl>
 </li>
 </ul>
 <a name="getWidth()">
@@ -648,14 +650,11 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getWidth</h4>
-<pre>public&nbsp;int&nbsp;getWidth()
-             throws java.lang.Exception</pre>
+<pre>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="strong">Returns:</span></dt><dd>the width of the source image (JPEG or YUV) associated with this
- decompressor instance.</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getHeight()">
@@ -664,14 +663,11 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getHeight</h4>
-<pre>public&nbsp;int&nbsp;getHeight()
-              throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getSubsamp()">
@@ -680,15 +676,12 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getSubsamp</h4>
-<pre>public&nbsp;int&nbsp;getSubsamp()
-               throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ (JPEG or YUV) associated with this decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getColorspace()">
@@ -697,15 +690,12 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getColorspace</h4>
-<pre>public&nbsp;int&nbsp;getColorspace()
-                  throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ with this decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getJPEGBuf()">
@@ -714,12 +704,9 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getJPEGBuf</h4>
-<pre>public&nbsp;byte[]&nbsp;getJPEGBuf()
-                  throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the JPEG image buffer associated with this decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getJPEGSize()">
@@ -728,14 +715,11 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getJPEGSize</h4>
-<pre>public&nbsp;int&nbsp;getJPEGSize()
-                throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ decompressor instance.</dd></dl>
 </li>
 </ul>
 <a name="getScaledWidth(int, int)">
@@ -745,8 +729,7 @@
 <li class="blockList">
 <h4>getScaledWidth</h4>
 <pre>public&nbsp;int&nbsp;getScaledWidth(int&nbsp;desiredWidth,
-                 int&nbsp;desiredHeight)
-                   throws java.lang.Exception</pre>
+                 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>
@@ -759,9 +742,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ height.</dd></dl>
 </li>
 </ul>
 <a name="getScaledHeight(int, int)">
@@ -771,8 +752,7 @@
 <li class="blockList">
 <h4>getScaledHeight</h4>
 <pre>public&nbsp;int&nbsp;getScaledHeight(int&nbsp;desiredWidth,
-                  int&nbsp;desiredHeight)
-                    throws java.lang.Exception</pre>
+                  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>
@@ -785,9 +765,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ height.</dd></dl>
 </li>
 </ul>
 <a name="decompress(byte[], int, int, int, int, int, int, int)">
@@ -804,7 +782,7 @@
               int&nbsp;desiredHeight,
               int&nbsp;pixelFormat,
               int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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.</div>
@@ -852,7 +830,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompress(byte[], int, int, int, int, int)">
@@ -868,11 +846,11 @@
                          int&nbsp;desiredHeight,
                          int&nbsp;pixelFormat,
                          int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompress(int, int, int, int, int)">
@@ -886,7 +864,7 @@
                 int&nbsp;desiredHeight,
                 int&nbsp;pixelFormat,
                 int&nbsp;flags)
-                  throws java.lang.Exception</pre>
+                  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
@@ -900,7 +878,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompressToYUV(org.libjpegturbo.turbojpeg.YUVImage, int)">
@@ -911,7 +889,7 @@
 <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 java.lang.Exception</pre>
+                     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
@@ -926,7 +904,7 @@
  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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompressToYUV(byte[], int)">
@@ -938,10 +916,10 @@
 <pre>@Deprecated
 public&nbsp;void&nbsp;decompressToYUV(byte[]&nbsp;dstBuf,
                               int&nbsp;flags)
-                     throws java.lang.Exception</pre>
+                     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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompressToYUV(int, int[], int, int)">
@@ -954,7 +932,7 @@
                        int[]&nbsp;strides,
                        int&nbsp;desiredHeight,
                        int&nbsp;flags)
-                         throws java.lang.Exception</pre>
+                         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.
@@ -984,7 +962,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompressToYUV(int, int, int, int)">
@@ -997,7 +975,7 @@
                        int&nbsp;pad,
                        int&nbsp;desiredHeight,
                        int&nbsp;flags)
-                         throws java.lang.Exception</pre>
+                         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
@@ -1023,7 +1001,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompressToYUV(int)">
@@ -1034,10 +1012,10 @@
 <h4>decompressToYUV</h4>
 <pre>@Deprecated
 public&nbsp;byte[]&nbsp;decompressToYUV(int&nbsp;flags)
-                       throws java.lang.Exception</pre>
+                       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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/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)">
@@ -1054,7 +1032,7 @@
               int&nbsp;desiredHeight,
               int&nbsp;pixelFormat,
               int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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.</div>
@@ -1100,7 +1078,7 @@
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompress(java.awt.image.BufferedImage, int)">
@@ -1111,7 +1089,7 @@
 <h4>decompress</h4>
 <pre>public&nbsp;void&nbsp;decompress(java.awt.image.BufferedImage&nbsp;dstImage,
               int&nbsp;flags)
-                throws java.lang.Exception</pre>
+                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.</div>
@@ -1124,7 +1102,7 @@
  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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="decompress(int, int, int, int)">
@@ -1137,7 +1115,7 @@
                                       int&nbsp;desiredHeight,
                                       int&nbsp;bufferedImageType,
                                       int&nbsp;flags)
-                                        throws java.lang.Exception</pre>
+                                        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>
@@ -1152,7 +1130,7 @@
 <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="close()">
@@ -1162,10 +1140,15 @@
 <li class="blockList">
 <h4>close</h4>
 <pre>public&nbsp;void&nbsp;close()
-           throws java.lang.Exception</pre>
+           throws <a href="../../../org/libjpegturbo/turbojpeg/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><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<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>
+<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>
 </li>
 </ul>
 <a name="finalize()">
@@ -1208,7 +1191,7 @@
 <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/TJScalingFactor.html" title="class in org.libjpegturbo.turbojpeg"><span class="strong">Next 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>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJException.html b/java/doc/org/libjpegturbo/turbojpeg/TJException.html
new file mode 100644
index 0000000..6088066
--- /dev/null
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJException.html
@@ -0,0 +1,287 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!-- NewPage -->
+<html lang="en">
+<head>
+<title>TJException</title>
+<link rel="stylesheet" type="text/css" href="../../../stylesheet.css" title="Style">
+</head>
+<body>
+<script type="text/javascript"><!--
+    if (location.href.indexOf('is-external=true') == -1) {
+        parent.document.title="TJException";
+    }
+//-->
+</script>
+<noscript>
+<div>JavaScript is disabled on your browser.</div>
+</noscript>
+<!-- ========= START OF TOP NAVBAR ======= -->
+<div class="topNav"><a name="navbar_top">
+<!--   -->
+</a><a href="#skip-navbar_top" title="Skip navigation links"></a><a name="navbar_top_firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="../../../org/libjpegturbo/turbojpeg/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>
+<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">
+<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>
+</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>
+</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="#methods_inherited_from_class_java.lang.Throwable">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>Method</li>
+</ul>
+</div>
+<a name="skip-navbar_top">
+<!--   -->
+</a></div>
+<!-- ========= END OF TOP NAVBAR ========= -->
+<!-- ======== START OF CLASS DATA ======== -->
+<div class="header">
+<div class="subTitle">org.libjpegturbo.turbojpeg</div>
+<h2 title="Class TJException" class="title">Class TJException</h2>
+</div>
+<div class="contentContainer">
+<ul class="inheritance">
+<li>java.lang.Object</li>
+<li>
+<ul class="inheritance">
+<li>java.lang.Throwable</li>
+<li>
+<ul class="inheritance">
+<li>java.lang.Exception</li>
+<li>
+<ul class="inheritance">
+<li>java.io.IOException</li>
+<li>
+<ul class="inheritance">
+<li>org.libjpegturbo.turbojpeg.TJException</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+<div class="description">
+<ul class="blockList">
+<li class="blockList">
+<dl>
+<dt>All Implemented Interfaces:</dt>
+<dd>java.io.Serializable</dd>
+</dl>
+<hr>
+<br>
+<pre>public class <span class="strong">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>
+</li>
+</ul>
+</div>
+<div class="summary">
+<ul class="blockList">
+<li class="blockList">
+<!-- ======== CONSTRUCTOR SUMMARY ======== -->
+<ul class="blockList">
+<li class="blockList"><a name="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">
+<caption><span>Constructors</span><span class="tabEnd">&nbsp;</span></caption>
+<tr>
+<th class="colOne" scope="col">Constructor and 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>
+</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>
+</tr>
+<tr class="altColor">
+<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>
+</tr>
+<tr class="rowColor">
+<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>
+</tr>
+</table>
+</li>
+</ul>
+<!-- ========== METHOD SUMMARY =========== -->
+<ul class="blockList">
+<li class="blockList"><a name="method_summary">
+<!--   -->
+</a>
+<h3>Method Summary</h3>
+<ul class="blockList">
+<li class="blockList"><a name="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">
+<!--   -->
+</a>
+<h3>Methods inherited from class&nbsp;java.lang.Object</h3>
+<code>clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait</code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="details">
+<ul class="blockList">
+<li class="blockList">
+<!-- ========= CONSTRUCTOR DETAIL ======== -->
+<ul class="blockList">
+<li class="blockList"><a name="constructor_detail">
+<!--   -->
+</a>
+<h3>Constructor Detail</h3>
+<a name="TJException()">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>TJException</h4>
+<pre>public&nbsp;TJException()</pre>
+</li>
+</ul>
+<a name="TJException(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>
+</li>
+</ul>
+<a name="TJException(java.lang.String)">
+<!--   -->
+</a>
+<ul class="blockList">
+<li class="blockList">
+<h4>TJException</h4>
+<pre>public&nbsp;TJException(java.lang.String&nbsp;message)</pre>
+</li>
+</ul>
+<a name="TJException(java.lang.Throwable)">
+<!--   -->
+</a>
+<ul class="blockListLast">
+<li class="blockList">
+<h4>TJException</h4>
+<pre>public&nbsp;TJException(java.lang.Throwable&nbsp;cause)</pre>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+<!-- ========= END OF CLASS DATA ========= -->
+<!-- ======= START OF BOTTOM NAVBAR ====== -->
+<div class="bottomNav"><a name="navbar_bottom">
+<!--   -->
+</a><a href="#skip-navbar_bottom" title="Skip navigation links"></a><a name="navbar_bottom_firstrow">
+<!--   -->
+</a>
+<ul class="navList" title="Navigation">
+<li><a href="../../../org/libjpegturbo/turbojpeg/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>
+<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">
+<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>
+</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>
+</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="#methods_inherited_from_class_java.lang.Throwable">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>Method</li>
+</ul>
+</div>
+<a name="skip-navbar_bottom">
+<!--   -->
+</a></div>
+<!-- ======== END OF BOTTOM NAVBAR ======= -->
+</body>
+</html>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
index c28c00c..35d6882 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
@@ -32,7 +32,7 @@
 </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/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">
@@ -192,10 +192,7 @@
 <li class="blockList">
 <h4>TJScalingFactor</h4>
 <pre>public&nbsp;TJScalingFactor(int&nbsp;num,
-               int&nbsp;denom)
-                throws java.lang.Exception</pre>
-<dl><dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+               int&nbsp;denom)</pre>
 </li>
 </ul>
 </li>
@@ -291,7 +288,7 @@
 </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/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">
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
index daabfb3..cf65bd2 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
@@ -608,8 +608,7 @@
            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)
-            throws java.lang.Exception</pre>
+           <a href="../../../org/libjpegturbo/turbojpeg/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
@@ -618,9 +617,7 @@
  <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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ (<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>
 </li>
 </ul>
 <a name="TJTransform(java.awt.Rectangle, int, int, org.libjpegturbo.turbojpeg.TJCustomFilter)">
@@ -632,15 +629,12 @@
 <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)
-            throws java.lang.Exception</pre>
+           <a href="../../../org/libjpegturbo/turbojpeg/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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ (<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>
 </li>
 </ul>
 </li>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
index 32c92bb..36cbdb1 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
@@ -95,6 +95,10 @@
 <div class="description">
 <ul class="blockList">
 <li class="blockList">
+<dl>
+<dt>All Implemented Interfaces:</dt>
+<dd>java.io.Closeable, java.lang.AutoCloseable</dd>
+</dl>
 <hr>
 <br>
 <pre>public class <span class="strong">TJTransformer</span>
@@ -228,10 +232,10 @@
 <li class="blockList">
 <h4>TJTransformer</h4>
 <pre>public&nbsp;TJTransformer()
-              throws java.lang.Exception</pre>
+              throws <a href="../../../org/libjpegturbo/turbojpeg/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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="TJTransformer(byte[])">
@@ -241,13 +245,13 @@
 <li class="blockList">
 <h4>TJTransformer</h4>
 <pre>public&nbsp;TJTransformer(byte[]&nbsp;jpegImage)
-              throws java.lang.Exception</pre>
+              throws <a href="../../../org/libjpegturbo/turbojpeg/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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="TJTransformer(byte[], int)">
@@ -258,13 +262,13 @@
 <h4>TJTransformer</h4>
 <pre>public&nbsp;TJTransformer(byte[]&nbsp;jpegImage,
              int&nbsp;imageSize)
-              throws java.lang.Exception</pre>
+              throws <a href="../../../org/libjpegturbo/turbojpeg/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
  <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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 </li>
@@ -284,7 +288,7 @@
 <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 java.lang.Exception</pre>
+               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
@@ -306,7 +310,7 @@
  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>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="transform(org.libjpegturbo.turbojpeg.TJTransform[], int)">
@@ -317,7 +321,7 @@
 <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 java.lang.Exception</pre>
+                           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>
@@ -328,7 +332,7 @@
 <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
  which has a transformed JPEG image associated with it.</dd>
 <dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dd><code><a href="../../../org/libjpegturbo/turbojpeg/TJException.html" title="class in org.libjpegturbo.turbojpeg">TJException</a></code></dd></dl>
 </li>
 </ul>
 <a name="getTransformedSizes()">
@@ -337,14 +341,11 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getTransformedSizes</h4>
-<pre>public&nbsp;int[]&nbsp;getTransformedSizes()
-                          throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ generated by the most recent transform operation.</dd></dl>
 </li>
 </ul>
 </li>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/YUVImage.html b/java/doc/org/libjpegturbo/turbojpeg/YUVImage.html
index 0a3e0a5..b2be0a0 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/YUVImage.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/YUVImage.html
@@ -434,8 +434,7 @@
 <pre>public&nbsp;YUVImage(int&nbsp;width,
         int[]&nbsp;strides,
         int&nbsp;height,
-        int&nbsp;subsamp)
-         throws java.lang.Exception</pre>
+        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
@@ -445,9 +444,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
 </li>
 </ul>
 <a name="YUVImage(int, int, int, int)">
@@ -459,15 +456,12 @@
 <pre>public&nbsp;YUVImage(int&nbsp;width,
         int&nbsp;pad,
         int&nbsp;height,
-        int&nbsp;subsamp)
-         throws java.lang.Exception</pre>
+        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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ 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)">
@@ -481,8 +475,7 @@
         int&nbsp;width,
         int[]&nbsp;strides,
         int&nbsp;height,
-        int&nbsp;subsamp)
-         throws java.lang.Exception</pre>
+        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)
@@ -503,9 +496,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ 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)">
@@ -518,8 +509,7 @@
         int&nbsp;width,
         int&nbsp;pad,
         int&nbsp;height,
-        int&nbsp;subsamp)
-         throws java.lang.Exception</pre>
+        int&nbsp;subsamp)</pre>
 <div class="block">Create a new <code>YUVImage</code> instance from an existing unified image
  buffer.</div>
 <dl><dt><span class="strong">Parameters:</span></dt><dd><code>yuvImage</code> - image buffer that contains or will contain YUV planar
@@ -529,9 +519,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
 </li>
 </ul>
 </li>
@@ -553,8 +541,7 @@
           int&nbsp;width,
           int[]&nbsp;strides,
           int&nbsp;height,
-          int&nbsp;subsamp)
-            throws java.lang.Exception</pre>
+          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)
  image planes (or just the Y plane, if the image is grayscale.)  These
@@ -574,9 +561,7 @@
  to each plane or to specify that this <code>YUVImage</code> image 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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
 </li>
 </ul>
 <a name="setBuf(byte[], int, int, int, int)">
@@ -589,8 +574,7 @@
           int&nbsp;width,
           int&nbsp;pad,
           int&nbsp;height,
-          int&nbsp;subsamp)
-            throws java.lang.Exception</pre>
+          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
@@ -599,9 +583,7 @@
  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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ image (one of <a href="../../../org/libjpegturbo/turbojpeg/TJ.html#SAMP_444"><code>TJ.SAMP_*</code></a>)</dd></dl>
 </li>
 </ul>
 <a name="getWidth()">
@@ -610,12 +592,9 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getWidth</h4>
-<pre>public&nbsp;int&nbsp;getWidth()
-             throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the width of the YUV image (or subregion)</dd></dl>
 </li>
 </ul>
 <a name="getHeight()">
@@ -624,12 +603,9 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getHeight</h4>
-<pre>public&nbsp;int&nbsp;getHeight()
-              throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the height of the YUV image (or subregion)</dd></dl>
 </li>
 </ul>
 <a name="getPad()">
@@ -638,13 +614,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getPad</h4>
-<pre>public&nbsp;int&nbsp;getPad()
-           throws java.lang.Exception</pre>
+<pre>public&nbsp;int&nbsp;getPad()</pre>
 <div class="block">Returns the line padding used in 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 line padding used in the YUV image buffer</dd>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the line padding used in the YUV image buffer</dd></dl>
 </li>
 </ul>
 <a name="getStrides()">
@@ -653,12 +626,9 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getStrides</h4>
-<pre>public&nbsp;int[]&nbsp;getStrides()
-                 throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the number of bytes per line of each plane in the YUV image</dd></dl>
 </li>
 </ul>
 <a name="getOffsets()">
@@ -667,14 +637,11 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getOffsets</h4>
-<pre>public&nbsp;int[]&nbsp;getOffsets()
-                 throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+ YUV image</dd></dl>
 </li>
 </ul>
 <a name="getSubsamp()">
@@ -683,13 +650,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getSubsamp</h4>
-<pre>public&nbsp;int&nbsp;getSubsamp()
-               throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the level of chrominance subsampling used in the YUV image</dd></dl>
 </li>
 </ul>
 <a name="getPlanes()">
@@ -698,13 +662,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getPlanes</h4>
-<pre>public&nbsp;byte[][]&nbsp;getPlanes()
-                   throws java.lang.Exception</pre>
+<pre>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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the YUV image planes</dd></dl>
 </li>
 </ul>
 <a name="getBuf()">
@@ -713,13 +674,10 @@
 <ul class="blockList">
 <li class="blockList">
 <h4>getBuf</h4>
-<pre>public&nbsp;byte[]&nbsp;getBuf()
-              throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the YUV image buffer</dd></dl>
 </li>
 </ul>
 <a name="getSize()">
@@ -728,13 +686,10 @@
 <ul class="blockListLast">
 <li class="blockList">
 <h4>getSize</h4>
-<pre>public&nbsp;int&nbsp;getSize()
-            throws java.lang.Exception</pre>
+<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>
-<dt><span class="strong">Throws:</span></dt>
-<dd><code>java.lang.Exception</code></dd></dl>
+<dl><dt><span class="strong">Returns:</span></dt><dd>the size (in bytes) of the YUV image buffer</dd></dl>
 </li>
 </ul>
 </li>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
index 7cb8fa0..08a8bf8 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
@@ -22,6 +22,10 @@
 <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>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
index ea36057..f94656e 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
@@ -134,6 +134,21 @@
 </tbody>
 </table>
 </li>
+<li class="blockList">
+<table class="packageSummary" border="0" cellpadding="3" cellspacing="0" summary="Exception Summary table, listing exceptions, and an explanation">
+<caption><span>Exception Summary</span><span class="tabEnd">&nbsp;</span></caption>
+<tr>
+<th class="colFirst" scope="col">Exception</th>
+<th class="colLast" scope="col">Description</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>
+<td class="colLast">&nbsp;</td>
+</tr>
+</tbody>
+</table>
+</li>
 </ul>
 </div>
 <!-- ======= START OF BOTTOM NAVBAR ====== -->
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
index 1033ee5..02a5cde 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
@@ -79,9 +79,22 @@
 </li>
 </ul>
 </li>
+<li type="circle">java.lang.Throwable (implements java.io.Serializable)
+<ul>
+<li type="circle">java.lang.Exception
+<ul>
+<li type="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>
+</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></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>
+<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)
 <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>
 </ul>
diff --git a/java/doc/overview-tree.html b/java/doc/overview-tree.html
index eae18a1..2ae76c6 100644
--- a/java/doc/overview-tree.html
+++ b/java/doc/overview-tree.html
@@ -83,9 +83,22 @@
 </li>
 </ul>
 </li>
+<li type="circle">java.lang.Throwable (implements java.io.Serializable)
+<ul>
+<li type="circle">java.lang.Exception
+<ul>
+<li type="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>
+</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></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>
+<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)
 <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>
 </ul>
diff --git a/java/doc/serialized-form.html b/java/doc/serialized-form.html
index bbe1805..846cabc 100644
--- a/java/doc/serialized-form.html
+++ b/java/doc/serialized-form.html
@@ -66,6 +66,15 @@
 <li class="blockList">
 <h2 title="Package">Package&nbsp;org.libjpegturbo.turbojpeg</h2>
 <ul class="blockList">
+<li class="blockList"><a name="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>
+<dl class="nameValue">
+<dt>serialVersionUID:</dt>
+<dd>1L</dd>
+</dl>
+</li>
 <li class="blockList"><a name="org.libjpegturbo.turbojpeg.TJTransform">
 <!--   -->
 </a>
diff --git a/java/org/libjpegturbo/turbojpeg/TJ.java b/java/org/libjpegturbo/turbojpeg/TJ.java
index 644a197..02d14c0 100644
--- a/java/org/libjpegturbo/turbojpeg/TJ.java
+++ b/java/org/libjpegturbo/turbojpeg/TJ.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2011-2013 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
  * modification, are permitted provided that the following conditions are met:
@@ -87,9 +88,8 @@
    * @return the MCU block width for the given level of chrominance
    * subsampling.
    */
-  public static int getMCUWidth(int subsamp) throws Exception {
-    if (subsamp < 0 || subsamp >= NUMSAMP)
-      throw new Exception("Invalid subsampling type");
+  public static int getMCUWidth(int subsamp) {
+    checkSubsampling(subsamp);
     return mcuWidth[subsamp];
   }
 
@@ -108,9 +108,8 @@
    * @return the MCU block height for the given level of chrominance
    * subsampling.
    */
-  public static int getMCUHeight(int subsamp) throws Exception {
-    if (subsamp < 0 || subsamp >= NUMSAMP)
-      throw new Exception("Invalid subsampling type");
+  public static int getMCUHeight(int subsamp) {
+    checkSubsampling(subsamp);
     return mcuHeight[subsamp];
   }
 
@@ -217,9 +216,8 @@
    *
    * @return the pixel size (in bytes) for the given pixel format.
    */
-  public static int getPixelSize(int pixelFormat) throws Exception {
-    if (pixelFormat < 0 || pixelFormat >= NUMPF)
-      throw new Exception("Invalid pixel format");
+  public static int getPixelSize(int pixelFormat) {
+    checkPixelFormat(pixelFormat);
     return pixelSize[pixelFormat];
   }
 
@@ -239,9 +237,8 @@
    *
    * @return the red offset for the given pixel format.
    */
-  public static int getRedOffset(int pixelFormat) throws Exception {
-    if (pixelFormat < 0 || pixelFormat >= NUMPF)
-      throw new Exception("Invalid pixel format");
+  public static int getRedOffset(int pixelFormat) {
+    checkPixelFormat(pixelFormat);
     return redOffset[pixelFormat];
   }
 
@@ -261,9 +258,8 @@
    *
    * @return the green offset for the given pixel format.
    */
-  public static int getGreenOffset(int pixelFormat) throws Exception {
-    if (pixelFormat < 0 || pixelFormat >= NUMPF)
-      throw new Exception("Invalid pixel format");
+  public static int getGreenOffset(int pixelFormat) {
+    checkPixelFormat(pixelFormat);
     return greenOffset[pixelFormat];
   }
 
@@ -283,9 +279,8 @@
    *
    * @return the blue offset for the given pixel format.
    */
-  public static int getBlueOffset(int pixelFormat) throws Exception {
-    if (pixelFormat < 0 || pixelFormat >= NUMPF)
-      throw new Exception("Invalid pixel format");
+  public static int getBlueOffset(int pixelFormat) {
+    checkPixelFormat(pixelFormat);
     return blueOffset[pixelFormat];
   }
 
@@ -407,8 +402,7 @@
    * @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.
    */
-  public static native int bufSize(int width, int height, int jpegSubsamp)
-    throws Exception;
+  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
@@ -428,15 +422,13 @@
    * image with the given width, height, and level of chrominance subsampling.
    */
   public static native int bufSizeYUV(int width, int pad, int height,
-                                      int subsamp)
-    throws Exception;
+                                      int subsamp);
 
   /**
    * @deprecated Use {@link #bufSizeYUV(int, int, int, int)} instead.
    */
   @Deprecated
-  public static native int bufSizeYUV(int width, int height, int subsamp)
-    throws Exception;
+  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
@@ -460,8 +452,7 @@
    * image with the given parameters.
    */
   public static native int planeSizeYUV(int componentID, int width, int stride,
-                                        int height, int subsamp)
-    throws Exception;
+                                        int height, int subsamp);
 
   /**
    * Returns the plane width of a YUV image plane with the given parameters.
@@ -477,8 +468,7 @@
    *
    * @return the plane width of a YUV image plane with the given parameters.
    */
-  public static native int planeWidth(int componentID, int width, int subsamp)
-    throws Exception;
+  public static native int planeWidth(int componentID, int width, int subsamp);
 
   /**
    * Returns the plane height of a YUV image plane with the given parameters.
@@ -495,8 +485,7 @@
    * @return the plane height of a YUV image plane with the given parameters.
    */
   public static native int planeHeight(int componentID, int height,
-                                       int subsamp)
-    throws Exception;
+                                       int subsamp);
 
   /**
    * Returns a list of fractional scaling factors that the JPEG decompressor in
@@ -505,10 +494,20 @@
    * @return a list of fractional scaling factors that the JPEG decompressor in
    * this implementation of TurboJPEG supports.
    */
-  public static native TJScalingFactor[] getScalingFactors()
-    throws Exception;
+  public static native TJScalingFactor[] getScalingFactors();
 
   static {
     TJLoader.load();
   }
-};
+
+  private static void checkPixelFormat(int pixelFormat) {
+    if (pixelFormat < 0 || pixelFormat >= NUMPF)
+      throw new IllegalArgumentException("Invalid pixel format");
+  }
+
+  private static void checkSubsampling(int subsamp) {
+    if (subsamp < 0 || subsamp >= NUMSAMP)
+      throw new IllegalArgumentException("Invalid subsampling type");
+  }
+
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJCompressor.java b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
index 6ec581a..2ff8e4d 100644
--- a/java/org/libjpegturbo/turbojpeg/TJCompressor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2011-2015 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
  * modification, are permitted provided that the following conditions are met:
@@ -30,11 +31,12 @@
 
 import java.awt.image.*;
 import java.nio.*;
+import java.io.*;
 
 /**
  * TurboJPEG compressor
  */
-public class TJCompressor {
+public class TJCompressor implements Closeable {
 
   private static final String NO_ASSOC_ERROR =
     "No source image is associated with this instance";
@@ -42,7 +44,7 @@
   /**
    * Create a TurboJPEG compressor instance.
    */
-  public TJCompressor() throws Exception {
+  public TJCompressor() throws TJException {
     init();
   }
 
@@ -67,7 +69,7 @@
    * {@link TJ#PF_RGB TJ.PF_*})
    */
   public TJCompressor(byte[] srcImage, int x, int y, int width, int pitch,
-                      int height, int pixelFormat) throws Exception {
+                      int height, int pixelFormat) throws TJException {
     setSourceImage(srcImage, x, y, width, pitch, height, pixelFormat);
   }
 
@@ -77,7 +79,7 @@
    */
   @Deprecated
   public TJCompressor(byte[] srcImage, int width, int pitch, int height,
-                      int pixelFormat) throws Exception {
+                      int pixelFormat) throws TJException {
     setSourceImage(srcImage, width, pitch, height, pixelFormat);
   }
 
@@ -102,7 +104,7 @@
    * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description
    */
   public TJCompressor(BufferedImage srcImage, int x, int y, int width,
-                      int height) throws Exception {
+                      int height) throws TJException {
     setSourceImage(srcImage, x, y, width, height);
   }
 
@@ -139,11 +141,11 @@
    */
   public void setSourceImage(byte[] srcImage, int x, int y, int width,
                              int pitch, int height, int pixelFormat)
-                             throws Exception {
+                             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 Exception("Invalid argument in setSourceImage()");
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     srcBuf = srcImage;
     srcWidth = width;
     if (pitch == 0)
@@ -164,7 +166,7 @@
    */
   @Deprecated
   public void setSourceImage(byte[] srcImage, int width, int pitch,
-                             int height, int pixelFormat) throws Exception {
+                             int height, int pixelFormat) throws TJException {
     setSourceImage(srcImage, 0, 0, width, pitch, height, pixelFormat);
     srcX = srcY = -1;
   }
@@ -191,16 +193,16 @@
    * height of the source image)
    */
   public void setSourceImage(BufferedImage srcImage, int x, int y, int width,
-                             int height) throws Exception {
+                             int height) throws TJException {
     if (handle == 0) init();
     if (srcImage == null || x < 0 || y < 0 || width < 0 || height < 0)
-      throw new Exception("Invalid argument in setSourceImage()");
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     srcX = x;
     srcY = y;
     srcWidth = (width == 0) ? srcImage.getWidth(): width;
     srcHeight = (height == 0) ? srcImage.getHeight() : height;
     if (x + width > srcImage.getWidth() || y + height > srcImage.getHeight())
-      throw new Exception("Compression region exceeds the bounds of the source image");
+      throw new IllegalArgumentException("Compression region exceeds the bounds of the source image");
 
     int pixelFormat;
     boolean intPixels = false;
@@ -229,7 +231,7 @@
           pixelFormat = TJ.PF_BGRX;
         intPixels = true;  break;
       default:
-        throw new Exception("Unsupported BufferedImage format");
+        throw new IllegalArgumentException("Unsupported BufferedImage format");
     }
     srcPixelFormat = pixelFormat;
 
@@ -246,7 +248,7 @@
         (ComponentSampleModel)srcImage.getSampleModel();
       int pixelSize = sm.getPixelStride();
       if (pixelSize != TJ.getPixelSize(pixelFormat))
-        throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
+        throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
       srcPitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       srcBuf = db.getData();
@@ -262,10 +264,10 @@
    * @param srcImage YUV planar image to be compressed.  This image is not
    * modified.
    */
-  public void setSourceImage(YUVImage srcImage) throws Exception {
+  public void setSourceImage(YUVImage srcImage) throws TJException {
     if (handle == 0) init();
     if (srcImage == null)
-      throw new Exception("Invalid argument in setSourceImage()");
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     srcYUVImage = srcImage;
     srcBuf = null;
     srcBufInt = null;
@@ -292,9 +294,9 @@
    * subsequent compress/encode oeprations (one of
    * {@link TJ#SAMP_444 TJ.SAMP_*})
    */
-  public void setSubsamp(int newSubsamp) throws Exception {
+  public void setSubsamp(int newSubsamp) {
     if (newSubsamp < 0 || newSubsamp >= TJ.NUMSAMP)
-      throw new Exception("Invalid argument in setSubsamp()");
+      throw new IllegalArgumentException("Invalid argument in setSubsamp()");
     subsamp = newSubsamp;
   }
 
@@ -304,9 +306,9 @@
    * @param quality the new JPEG image quality level (1 to 100, 1 = worst,
    * 100 = best)
    */
-  public void setJPEGQuality(int quality) throws Exception {
+  public void setJPEGQuality(int quality) {
     if (quality < 1 || quality > 100)
-      throw new Exception("Invalid argument in setJPEGQuality()");
+      throw new IllegalArgumentException("Invalid argument in setJPEGQuality()");
     jpegQuality = quality;
   }
 
@@ -322,15 +324,15 @@
    * @param flags the bitwise OR of one or more of
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
-  public void compress(byte[] dstBuf, int flags) throws Exception {
+  public void compress(byte[] dstBuf, int flags) throws TJException {
     if (dstBuf == null || flags < 0)
-      throw new Exception("Invalid argument in compress()");
+      throw new IllegalArgumentException("Invalid argument in compress()");
     if (srcBuf == null && srcBufInt == null && srcYUVImage == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegQuality < 0)
-      throw new Exception("JPEG Quality not set");
+      throw new IllegalStateException("JPEG Quality not set");
     if (subsamp < 0 && srcYUVImage == null)
-      throw new Exception("Subsampling level not set");
+      throw new IllegalStateException("Subsampling level not set");
 
     if (srcYUVImage != null)
       compressedSize = compressFromYUV(srcYUVImage.getPlanes(),
@@ -372,9 +374,8 @@
    * 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 Exception {
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+  public byte[] compress(int flags) throws TJException {
+    checkSourceImage();
     byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)];
     compress(buf, flags);
     return buf;
@@ -387,7 +388,7 @@
    */
   @Deprecated
   public void compress(BufferedImage srcImage, byte[] dstBuf, int flags)
-                       throws Exception {
+                       throws TJException {
     setSourceImage(srcImage, 0, 0, 0, 0);
     compress(dstBuf, flags);
   }
@@ -398,7 +399,8 @@
    * {@link #compress(int)} instead.
    */
   @Deprecated
-  public byte[] compress(BufferedImage srcImage, int flags) throws Exception {
+  public byte[] compress(BufferedImage srcImage, int flags)
+                         throws TJException {
     setSourceImage(srcImage, 0, 0, 0, 0);
     return compress(flags);
   }
@@ -417,17 +419,16 @@
    * @param flags the bitwise OR of one or more of
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
-  public void encodeYUV(YUVImage dstImage, int flags) throws Exception {
+  public void encodeYUV(YUVImage dstImage, int flags) throws TJException {
     if (dstImage == null || flags < 0)
-      throw new Exception("Invalid argument in encodeYUV()");
+      throw new IllegalArgumentException("Invalid argument in encodeYUV()");
     if (srcBuf == null && srcBufInt == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (srcYUVImage != null)
-      throw new Exception("Source image is not correct type");
-    if (subsamp < 0)
-      throw new Exception("Subsampling level not set");
+      throw new IllegalStateException("Source image is not correct type");
+    checkSubsampling();
     if (srcWidth != dstImage.getWidth() || srcHeight != dstImage.getHeight())
-      throw new Exception("Destination image is the wrong size");
+      throw new IllegalStateException("Destination image is the wrong size");
 
     if (srcBufInt != null) {
       encodeYUV(srcBufInt, srcX, srcY, srcWidth, srcStride, srcHeight,
@@ -445,13 +446,11 @@
    * @deprecated Use {@link #encodeYUV(YUVImage, int)} instead.
    */
   @Deprecated
-  public void encodeYUV(byte[] dstBuf, int flags) throws Exception {
+  public void encodeYUV(byte[] dstBuf, int flags) throws TJException {
     if(dstBuf == null)
-      throw new Exception("Invalid argument in encodeYUV()");
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
-    if (subsamp < 0)
-      throw new Exception("Subsampling level not set");
+      throw new IllegalArgumentException("Invalid argument in encodeYUV()");
+    checkSourceImage();
+    checkSubsampling();
     YUVImage yuvImage = new YUVImage(dstBuf, srcWidth, 4, srcHeight, subsamp);
     encodeYUV(yuvImage, flags);
   }
@@ -473,13 +472,11 @@
    *
    * @return a YUV planar image.
    */
-  public YUVImage encodeYUV(int pad, int flags) throws Exception {
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
-    if (subsamp < 0)
-      throw new Exception("Subsampling level not set");
+  public YUVImage encodeYUV(int pad, int flags) throws TJException {
+    checkSourceImage();
+    checkSubsampling();
     if(pad < 1 || ((pad & (pad - 1)) != 0))
-      throw new Exception("Invalid argument in encodeYUV()");
+      throw new IllegalStateException("Invalid argument in encodeYUV()");
     YUVImage yuvImage = new YUVImage(srcWidth, pad, srcHeight, subsamp);
     encodeYUV(yuvImage, flags);
     return yuvImage;
@@ -506,11 +503,9 @@
    *
    * @return a YUV planar image.
    */
-  public YUVImage encodeYUV(int[] strides, int flags) throws Exception {
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
-    if (subsamp < 0)
-      throw new Exception("Subsampling level not set");
+  public YUVImage encodeYUV(int[] strides, int flags) throws TJException {
+    checkSourceImage();
+    checkSubsampling();
     YUVImage yuvImage = new YUVImage(srcWidth, strides, srcHeight, subsamp);
     encodeYUV(yuvImage, flags);
     return yuvImage;
@@ -520,11 +515,9 @@
    * @deprecated Use {@link #encodeYUV(int, int)} instead.
    */
   @Deprecated
-  public byte[] encodeYUV(int flags) throws Exception {
-    if (srcWidth < 1 || srcHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
-    if (subsamp < 0)
-      throw new Exception("Subsampling level not set");
+  public byte[] encodeYUV(int flags) throws TJException {
+    checkSourceImage();
+    checkSubsampling();
     YUVImage yuvImage = new YUVImage(srcWidth, 4, srcHeight, subsamp);
     encodeYUV(yuvImage, flags);
     return yuvImage.getBuf();
@@ -537,7 +530,7 @@
    */
   @Deprecated
   public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags)
-    throws Exception {
+                        throws TJException {
     setSourceImage(srcImage, 0, 0, 0, 0);
     encodeYUV(dstBuf, flags);
   }
@@ -548,7 +541,8 @@
    * {@link #encodeYUV(int, int)} instead.
    */
   @Deprecated
-  public byte[] encodeYUV(BufferedImage srcImage, int flags) throws Exception {
+  public byte[] encodeYUV(BufferedImage srcImage, int flags)
+                          throws TJException {
     setSourceImage(srcImage, 0, 0, 0, 0);
     return encodeYUV(flags);
   }
@@ -567,68 +561,84 @@
   /**
    * Free the native structures associated with this compressor instance.
    */
-  public void close() throws Exception {
+  @Override
+  public void close() throws TJException {
     if (handle != 0)
       destroy();
   }
 
+  @Override
   protected void finalize() throws Throwable {
     try {
       close();
-    } catch(Exception e) {
+    } catch(TJException e) {
     } finally {
       super.finalize();
     }
   };
 
-  private native void init() throws Exception;
+  private native void init() throws TJException;
 
-  private native void destroy() throws Exception;
+  private native void destroy() throws TJException;
 
   // JPEG size in bytes is returned
+  @Deprecated
   private native int compress(byte[] srcBuf, int width, int pitch,
     int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
-    int flags) throws Exception; // deprecated
+    int flags) throws TJException;
 
   private native int compress(byte[] srcBuf, int x, int y, int width,
     int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
-    int jpegQual, int flags) throws Exception;
+    int jpegQual, int flags) throws TJException;
 
+  @Deprecated
   private native int compress(int[] srcBuf, int width, int stride,
     int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
-    int flags) throws Exception; // deprecated
+    int flags) throws TJException;
 
   private native int compress(int[] srcBuf, int x, int y, int width,
     int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
-    int jpegQual, int flags) throws Exception;
+    int jpegQual, int flags) throws TJException;
 
   private native int compressFromYUV(byte[][] srcPlanes, int[] srcOffsets,
     int width, int[] srcStrides, int height, int subsamp, byte[] dstBuf,
     int jpegQual, int flags)
-    throws Exception;
+    throws TJException;
 
+  @Deprecated
   private native void encodeYUV(byte[] srcBuf, int width, int pitch,
     int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
-    throws Exception; // deprecated
+    throws TJException;
 
   private native void encodeYUV(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 Exception;
+    throws TJException;
 
+  @Deprecated
   private native void encodeYUV(int[] srcBuf, int width, int stride,
     int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
-    throws Exception; // deprecated
+    throws TJException;
 
   private native void encodeYUV(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 Exception;
+    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 int[] srcBufInt = null;
@@ -645,4 +655,4 @@
   private int compressedSize = 0;
   private int yuvPad = 4;
   private ByteOrder byteOrder = null;
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJCustomFilter.java b/java/org/libjpegturbo/turbojpeg/TJCustomFilter.java
index bf78f2e..9a34587 100644
--- a/java/org/libjpegturbo/turbojpeg/TJCustomFilter.java
+++ b/java/org/libjpegturbo/turbojpeg/TJCustomFilter.java
@@ -72,5 +72,5 @@
   void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
                     Rectangle planeRegion, int componentID, int transformID,
                     TJTransform transform)
-    throws Exception;
+    throws TJException;
 }
diff --git a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
index 7ec557f..bd0e694 100644
--- a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2011-2015 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
  * modification, are permitted provided that the following conditions are met:
@@ -30,11 +31,12 @@
 
 import java.awt.image.*;
 import java.nio.*;
+import java.io.*;
 
 /**
  * TurboJPEG decompressor
  */
-public class TJDecompressor {
+public class TJDecompressor implements Closeable {
 
   private static final String NO_ASSOC_ERROR =
     "No JPEG image is associated with this instance";
@@ -42,7 +44,7 @@
   /**
    * Create a TurboJPEG decompresssor instance.
    */
-  public TJDecompressor() throws Exception {
+  public TJDecompressor() throws TJException {
     init();
   }
 
@@ -53,7 +55,7 @@
    * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
    * be the length of the array.)  This buffer is not modified.
    */
-  public TJDecompressor(byte[] jpegImage) throws Exception {
+  public TJDecompressor(byte[] jpegImage) throws TJException {
     init();
     setSourceImage(jpegImage, jpegImage.length);
   }
@@ -67,7 +69,7 @@
    *
    * @param imageSize size of the JPEG image (in bytes)
    */
-  public TJDecompressor(byte[] jpegImage, int imageSize) throws Exception {
+  public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
     init();
     setSourceImage(jpegImage, imageSize);
   }
@@ -80,7 +82,7 @@
    * @param yuvImage {@link YUVImage} instance containing a YUV planar
    * image to be decoded.  This image is not modified.
    */
-  public TJDecompressor(YUVImage yuvImage) throws Exception {
+  public TJDecompressor(YUVImage yuvImage) throws TJException {
     init();
     setSourceImage(yuvImage);
   }
@@ -95,9 +97,9 @@
    * @param imageSize size of the JPEG image (in bytes)
    */
   public void setSourceImage(byte[] jpegImage, int imageSize)
-    throws Exception {
+                             throws TJException {
     if (jpegImage == null || imageSize < 1)
-      throw new Exception("Invalid argument in setSourceImage()");
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     jpegBuf = jpegImage;
     jpegBufSize = imageSize;
     decompressHeader(jpegBuf, jpegBufSize);
@@ -108,7 +110,8 @@
    * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
    */
   @Deprecated
-  public void setJPEGImage(byte[] jpegImage, int imageSize) throws Exception {
+  public void setJPEGImage(byte[] jpegImage, int imageSize)
+                           throws TJException {
     setSourceImage(jpegImage, imageSize);
   }
 
@@ -120,9 +123,9 @@
    * @param srcImage {@link YUVImage} instance containing a YUV planar image to
    * be decoded.  This image is not modified.
    */
-  public void setSourceImage(YUVImage srcImage) throws Exception {
+  public void setSourceImage(YUVImage srcImage) {
     if (srcImage == null)
-      throw new Exception("Invalid argument in setSourceImage()");
+      throw new IllegalArgumentException("Invalid argument in setSourceImage()");
     yuvImage = srcImage;
     jpegBuf = null;
     jpegBufSize = 0;
@@ -136,11 +139,11 @@
    * @return the width of the source image (JPEG or YUV) associated with this
    * decompressor instance.
    */
-  public int getWidth() throws Exception {
+  public int getWidth() {
     if (yuvImage != null)
       return yuvImage.getWidth();
     if (jpegWidth < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegWidth;
   }
 
@@ -151,11 +154,11 @@
    * @return the height of the source image (JPEG or YUV) associated with this
    * decompressor instance.
    */
-  public int getHeight() throws Exception {
+  public int getHeight() {
     if (yuvImage != null)
       return yuvImage.getHeight();
     if (jpegHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegHeight;
   }
 
@@ -167,13 +170,13 @@
    * @return the level of chrominance subsampling used in the source image
    * (JPEG or YUV) associated with this decompressor instance.
    */
-  public int getSubsamp() throws Exception {
+  public int getSubsamp() {
     if (yuvImage != null)
       return yuvImage.getSubsamp();
     if (jpegSubsamp < 0)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegSubsamp >= TJ.NUMSAMP)
-      throw new Exception("JPEG header information is invalid");
+      throw new IllegalStateException("JPEG header information is invalid");
     return jpegSubsamp;
   }
 
@@ -185,13 +188,13 @@
    * @return the colorspace used in the source image (JPEG or YUV) associated
    * with this decompressor instance.
    */
-  public int getColorspace() throws Exception {
+  public int getColorspace() {
     if (yuvImage != null)
       return TJ.CS_YCbCr;
     if (jpegColorspace < 0)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegColorspace >= TJ.NUMCS)
-      throw new Exception("JPEG header information is invalid");
+      throw new IllegalStateException("JPEG header information is invalid");
     return jpegColorspace;
   }
 
@@ -200,9 +203,9 @@
    *
    * @return the JPEG image buffer associated with this decompressor instance.
    */
-  public byte[] getJPEGBuf() throws Exception {
+  public byte[] getJPEGBuf() {
     if (jpegBuf == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegBuf;
   }
 
@@ -213,9 +216,9 @@
    * @return the size of the JPEG image (in bytes) associated with this
    * decompressor instance.
    */
-  public int getJPEGSize() throws Exception {
+  public int getJPEGSize() {
     if (jpegBufSize < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return jpegBufSize;
   }
 
@@ -238,12 +241,11 @@
    * decompressor can generate without exceeding the desired image width and
    * height.
    */
-  public int getScaledWidth(int desiredWidth, int desiredHeight)
-                            throws Exception {
+  public int getScaledWidth(int desiredWidth, int desiredHeight) {
     if (jpegWidth < 1 || jpegHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (desiredWidth < 0 || desiredHeight < 0)
-      throw new Exception("Invalid argument in getScaledWidth()");
+      throw new IllegalArgumentException("Invalid argument in getScaledWidth()");
     TJScalingFactor[] sf = TJ.getScalingFactors();
     if (desiredWidth == 0)
       desiredWidth = jpegWidth;
@@ -257,7 +259,7 @@
         break;
     }
     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
-      throw new Exception("Could not scale down to desired image dimensions");
+      throw new IllegalArgumentException("Could not scale down to desired image dimensions");
     return scaledWidth;
   }
 
@@ -280,12 +282,11 @@
    * decompressor can generate without exceeding the desired image width and
    * height.
    */
-  public int getScaledHeight(int desiredWidth, int desiredHeight)
-                             throws Exception {
+  public int getScaledHeight(int desiredWidth, int desiredHeight) {
     if (jpegWidth < 1 || jpegHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (desiredWidth < 0 || desiredHeight < 0)
-      throw new Exception("Invalid argument in getScaledHeight()");
+      throw new IllegalArgumentException("Invalid argument in getScaledHeight()");
     TJScalingFactor[] sf = TJ.getScalingFactors();
     if (desiredWidth == 0)
       desiredWidth = jpegWidth;
@@ -299,7 +300,7 @@
         break;
     }
     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
-      throw new Exception("Could not scale down to desired image dimensions");
+      throw new IllegalArgumentException("Could not scale down to desired image dimensions");
     return scaledHeight;
   }
 
@@ -369,13 +370,13 @@
    */
   public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
                          int pitch, int desiredHeight, int pixelFormat,
-                         int flags) throws Exception {
+                         int flags) throws TJException {
     if (jpegBuf == null && yuvImage == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      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)
-      throw new Exception("Invalid argument in decompress()");
+      throw new IllegalArgumentException("Invalid argument in decompress()");
     if (yuvImage != null)
       decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
                 yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
@@ -398,7 +399,7 @@
   @Deprecated
   public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
                          int desiredHeight, int pixelFormat, int flags)
-                         throws Exception {
+                         throws TJException {
     decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
                flags);
   }
@@ -428,11 +429,11 @@
    * @return a buffer containing the decompressed image.
    */
   public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
-                           int pixelFormat, int flags) throws Exception {
+                           int pixelFormat, int flags) throws TJException {
     if (pitch < 0 ||
         (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
         pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
-      throw new Exception("Invalid argument in decompress()");
+      throw new IllegalArgumentException("Invalid argument in decompress()");
     int pixelSize = TJ.getPixelSize(pixelFormat);
     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
@@ -461,20 +462,21 @@
    * @param flags the bitwise OR of one or more of
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
-  public void decompressToYUV(YUVImage dstImage, int flags) throws Exception {
+  public void decompressToYUV(YUVImage dstImage, int flags)
+                              throws TJException {
     if (jpegBuf == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (dstImage == null || flags < 0)
-      throw new Exception("Invalid argument in decompressToYUV()");
+      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 Exception("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
+      throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
     if (jpegSubsamp != dstImage.getSubsamp())
-      throw new Exception("YUVImage subsampling level does not match that of the JPEG image");
+      throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
 
     decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
                     dstImage.getOffsets(), dstImage.getWidth(),
@@ -485,7 +487,7 @@
    * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
    */
   @Deprecated
-  public void decompressToYUV(byte[] dstBuf, int flags) throws Exception {
+  public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
     YUVImage dstImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
                                      jpegSubsamp);
     decompressToYUV(dstImage, flags);
@@ -531,15 +533,15 @@
    */
   public YUVImage decompressToYUV(int desiredWidth, int[] strides,
                                   int desiredHeight,
-                                  int flags) throws Exception {
+                                  int flags) throws TJException {
     if (flags < 0)
-      throw new Exception("Invalid argument in decompressToYUV()");
+      throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
     if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegSubsamp >= TJ.NUMSAMP)
-      throw new Exception("JPEG header information is invalid");
+      throw new IllegalStateException("JPEG header information is invalid");
     if (yuvImage != null)
-      throw new Exception("Source image is the wrong type");
+      throw new IllegalStateException("Source image is the wrong type");
 
     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
@@ -584,15 +586,15 @@
    * @return a YUV planar image.
    */
   public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
-                                  int flags) throws Exception {
+                                  int flags) throws TJException {
     if (flags < 0)
-      throw new Exception("Invalid argument in decompressToYUV()");
+      throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
     if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (jpegSubsamp >= TJ.NUMSAMP)
-      throw new Exception("JPEG header information is invalid");
+      throw new IllegalStateException("JPEG header information is invalid");
     if (yuvImage != null)
-      throw new Exception("Source image is the wrong type");
+      throw new IllegalStateException("Source image is the wrong type");
 
     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
@@ -606,7 +608,7 @@
    * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
    */
   @Deprecated
-  public byte[] decompressToYUV(int flags) throws Exception {
+  public byte[] decompressToYUV(int flags) throws TJException {
     YUVImage dstImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
     decompressToYUV(dstImage, flags);
     return dstImage.getBuf();
@@ -676,13 +678,13 @@
    */
   public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
                          int stride, int desiredHeight, int pixelFormat,
-                         int flags) throws Exception {
+                         int flags) throws TJException {
     if (jpegBuf == null && yuvImage == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      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)
-      throw new Exception("Invalid argument in decompress()");
+      throw new IllegalArgumentException("Invalid argument in decompress()");
     if (yuvImage != null)
       decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
                 yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
@@ -709,9 +711,10 @@
    * @param flags the bitwise OR of one or more of
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
-  public void decompress(BufferedImage dstImage, int flags) throws Exception {
+  public void decompress(BufferedImage dstImage, int flags)
+                         throws TJException {
     if (dstImage == null || flags < 0)
-      throw new Exception("Invalid argument in decompress()");
+      throw new IllegalArgumentException("Invalid argument in decompress()");
     int desiredWidth = dstImage.getWidth();
     int desiredHeight = dstImage.getHeight();
     int scaledWidth, scaledHeight;
@@ -719,14 +722,14 @@
     if (yuvImage != null) {
       if (desiredWidth != yuvImage.getWidth() ||
           desiredHeight != yuvImage.getHeight())
-        throw new Exception("BufferedImage dimensions do not match the dimensions of the source image.");
+        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 Exception("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
+        throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
     }
     int pixelFormat;  boolean intPixels = false;
     if (byteOrder == null)
@@ -759,7 +762,7 @@
           pixelFormat = TJ.PF_BGRA;
         intPixels = true;  break;
       default:
-        throw new Exception("Unsupported BufferedImage format");
+        throw new IllegalArgumentException("Unsupported BufferedImage format");
     }
     WritableRaster wr = dstImage.getRaster();
     if (intPixels) {
@@ -775,7 +778,7 @@
                   pixelFormat, flags);
       else {
         if (jpegBuf == null)
-          throw new Exception(NO_ASSOC_ERROR);
+          throw new IllegalStateException(NO_ASSOC_ERROR);
         decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
                    scaledHeight, pixelFormat, flags);
       }
@@ -784,7 +787,7 @@
         (ComponentSampleModel)dstImage.getSampleModel();
       int pixelSize = sm.getPixelStride();
       if (pixelSize != TJ.getPixelSize(pixelFormat))
-        throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
+        throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
       int pitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       byte[] buf = db.getData();
@@ -818,10 +821,10 @@
    */
   public BufferedImage decompress(int desiredWidth, int desiredHeight,
                                   int bufferedImageType, int flags)
-                                  throws Exception {
+                                  throws TJException {
     if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
         flags < 0)
-      throw new Exception("Invalid argument in decompress()");
+      throw new IllegalArgumentException("Invalid argument in decompress()");
     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
     BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
@@ -833,57 +836,62 @@
   /**
    * Free the native structures associated with this decompressor instance.
    */
-  public void close() throws Exception {
+  @Override
+  public void close() throws TJException {
     if (handle != 0)
       destroy();
   }
 
+  @Override
   protected void finalize() throws Throwable {
     try {
       close();
-    } catch(Exception e) {
+    } catch(TJException e) {
     } finally {
       super.finalize();
     }
   };
 
-  private native void init() throws Exception;
+  private native void init() throws TJException;
 
-  private native void destroy() throws Exception;
+  private native void destroy() throws TJException;
 
   private native void decompressHeader(byte[] srcBuf, int size)
-    throws Exception;
+    throws TJException;
 
+  @Deprecated
   private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
     int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
-    throws Exception; // deprecated
+    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 Exception;
+    int flags) throws TJException;
 
+  @Deprecated
   private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
     int desiredWidth, int stride, int desiredHeight, int pixelFormat,
-    int flags) throws Exception; // deprecated
+    int flags) 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 Exception;
+    int flags) throws TJException;
 
+  @Deprecated
   private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
-    int flags) throws Exception; // deprecated
+    int flags) throws TJException;
 
   private native void decompressToYUV(byte[] srcBuf, int size,
     byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
-    int desiredheight, int flags) throws Exception;
+    int desiredheight, int flags) 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 Exception;
+    int pitch, int height, int pixelFormat, int flags) 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 Exception;
+    int stride, int height, int pixelFormat, int flags) throws TJException;
 
   static {
     TJLoader.load();
@@ -898,4 +906,4 @@
   protected int jpegSubsamp = -1;
   protected int jpegColorspace = -1;
   private ByteOrder byteOrder = null;
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJException.java b/java/org/libjpegturbo/turbojpeg/TJException.java
new file mode 100644
index 0000000..59c2041
--- /dev/null
+++ b/java/org/libjpegturbo/turbojpeg/TJException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C)2015 Viktor Szathmáry.  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.
+ */
+
+package org.libjpegturbo.turbojpeg;
+
+import java.io.IOException;
+
+public class TJException extends IOException {
+
+  private static final long serialVersionUID = 1L;
+
+  public TJException() {
+    super();
+  }
+
+  public TJException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  public TJException(String message) {
+    super(message);
+  }
+
+  public TJException(Throwable cause) {
+    super(cause);
+  }
+
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJLoader.java.in b/java/org/libjpegturbo/turbojpeg/TJLoader.java.in
index 22353a5..8397780 100644
--- a/java/org/libjpegturbo/turbojpeg/TJLoader.java.in
+++ b/java/org/libjpegturbo/turbojpeg/TJLoader.java.in
@@ -32,4 +32,4 @@
   static void load() {
     System.loadLibrary("@TURBOJPEG_DLL_NAME@");
   }
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJLoader.java.tmpl b/java/org/libjpegturbo/turbojpeg/TJLoader.java.tmpl
index a4f1c87..5ef3118 100644
--- a/java/org/libjpegturbo/turbojpeg/TJLoader.java.tmpl
+++ b/java/org/libjpegturbo/turbojpeg/TJLoader.java.tmpl
@@ -56,4 +56,4 @@
       }
     }
   }
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java b/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
index e00fdf7..ddb1d75 100644
--- a/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJScalingFactor.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2011 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
  * modification, are permitted provided that the following conditions are met:
@@ -33,9 +34,9 @@
  */
 public class TJScalingFactor {
 
-  public TJScalingFactor(int num, int denom) throws Exception {
+  public TJScalingFactor(int num, int denom) {
     if (num < 1 || denom < 1)
-      throw new Exception("Numerator and denominator must be >= 1");
+      throw new IllegalArgumentException("Numerator and denominator must be >= 1");
     this.num = num;
     this.denom = denom;
   }
@@ -77,7 +78,7 @@
    * <code>other</code> have the same numerator and denominator.
    */
   public boolean equals(TJScalingFactor other) {
-    return (this.num == other.num && this.denom == other.denom);
+    return this.num == other.num && this.denom == other.denom;
   }
 
   /**
@@ -88,7 +89,7 @@
    * 1/1.
    */
   public boolean isOne() {
-    return (num == 1 && denom == 1);
+    return num == 1 && denom == 1;
   }
 
   /**
@@ -100,4 +101,4 @@
    * Denominator
    */
   private int denom = 1;
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/TJTransform.java b/java/org/libjpegturbo/turbojpeg/TJTransform.java
index b464ffd..7381f36 100644
--- a/java/org/libjpegturbo/turbojpeg/TJTransform.java
+++ b/java/org/libjpegturbo/turbojpeg/TJTransform.java
@@ -160,7 +160,7 @@
    * TJCustomFilter} interface, or null if no custom filter is needed
    */
   public TJTransform(int x, int y, int w, int h, int op, int options,
-                     TJCustomFilter cf) throws Exception {
+                     TJCustomFilter cf) {
     super(x, y, w, h);
     this.op = op;
     this.options = options;
@@ -184,7 +184,7 @@
    * TJCustomFilter} interface, or null if no custom filter is needed
    */
   public TJTransform(Rectangle r, int op, int options,
-                     TJCustomFilter cf) throws Exception {
+                     TJCustomFilter cf) {
     super(r);
     this.op = op;
     this.options = options;
diff --git a/java/org/libjpegturbo/turbojpeg/TJTransformer.java b/java/org/libjpegturbo/turbojpeg/TJTransformer.java
index 2e17344..d76647f 100644
--- a/java/org/libjpegturbo/turbojpeg/TJTransformer.java
+++ b/java/org/libjpegturbo/turbojpeg/TJTransformer.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2011, 2013-2015 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
  * modification, are permitted provided that the following conditions are met:
@@ -36,7 +37,7 @@
   /**
    * Create a TurboJPEG lossless transformer instance.
    */
-  public TJTransformer() throws Exception {
+  public TJTransformer() throws TJException {
     init();
   }
 
@@ -47,7 +48,7 @@
    * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
    * be the length of the array.)  This buffer is not modified.
    */
-  public TJTransformer(byte[] jpegImage) throws Exception {
+  public TJTransformer(byte[] jpegImage) throws TJException {
     init();
     setSourceImage(jpegImage, jpegImage.length);
   }
@@ -61,7 +62,7 @@
    *
    * @param imageSize size of the JPEG image (in bytes)
    */
-  public TJTransformer(byte[] jpegImage, int imageSize) throws Exception {
+  public TJTransformer(byte[] jpegImage, int imageSize) throws TJException {
     init();
     setSourceImage(jpegImage, imageSize);
   }
@@ -94,9 +95,9 @@
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
   public void transform(byte[][] dstBufs, TJTransform[] transforms,
-                        int flags) throws Exception {
+                        int flags) throws TJException {
     if (jpegBuf == null)
-      throw new Exception("JPEG buffer not initialized");
+      throw new IllegalStateException("JPEG buffer not initialized");
     transformedSizes = transform(jpegBuf, jpegBufSize, dstBufs, transforms,
                                  flags);
   }
@@ -117,10 +118,10 @@
    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    */
   public TJDecompressor[] transform(TJTransform[] transforms, int flags)
-    throws Exception {
+                                    throws TJException {
     byte[][] dstBufs = new byte[transforms.length][];
     if (jpegWidth < 1 || jpegHeight < 1)
-      throw new Exception("JPEG buffer not initialized");
+      throw new IllegalStateException("JPEG buffer not initialized");
     for (int i = 0; i < transforms.length; i++) {
       int w = jpegWidth, h = jpegHeight;
       if ((transforms[i].options & TJTransform.OPT_CROP) != 0) {
@@ -143,20 +144,20 @@
    * @return an array containing the sizes of the transformed JPEG images
    * generated by the most recent transform operation.
    */
-  public int[] getTransformedSizes() throws Exception {
+  public int[] getTransformedSizes() {
     if (transformedSizes == null)
-      throw new Exception("No image has been transformed yet");
+      throw new IllegalStateException("No image has been transformed yet");
     return transformedSizes;
   }
 
-  private native void init() throws Exception;
+  private native void init() throws TJException;
 
   private native int[] transform(byte[] srcBuf, int srcSize, byte[][] dstBufs,
-    TJTransform[] transforms, int flags) throws Exception;
+    TJTransform[] transforms, int flags) throws TJException;
 
   static {
     TJLoader.load();
   }
 
   private int[] transformedSizes = null;
-};
+}
diff --git a/java/org/libjpegturbo/turbojpeg/YUVImage.java b/java/org/libjpegturbo/turbojpeg/YUVImage.java
index 2d790e9..1a05e62 100644
--- a/java/org/libjpegturbo/turbojpeg/YUVImage.java
+++ b/java/org/libjpegturbo/turbojpeg/YUVImage.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C)2014 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
  * modification, are permitted provided that the following conditions are met:
@@ -86,8 +87,7 @@
    * @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[] strides, int height, int subsamp)
-    throws Exception {
+  public YUVImage(int width, int[] strides, int height, int subsamp) {
     setBuf(null, null, width, strides, height, subsamp, true);
   }
 
@@ -105,8 +105,7 @@
    * @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)
-    throws Exception {
+  public YUVImage(int width, int pad, int height, int subsamp) {
     setBuf(new byte[TJ.bufSizeYUV(width, pad, height, subsamp)], width, pad,
            height, subsamp);
   }
@@ -146,7 +145,7 @@
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
   public YUVImage(byte[][] planes, int[] offsets, int width, int[] strides,
-                  int height, int subsamp) throws Exception {
+                  int height, int subsamp) {
     setBuf(planes, offsets, width, strides, height, subsamp, false);
   }
 
@@ -172,7 +171,7 @@
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
   public YUVImage(byte[] yuvImage, int width, int pad, int height,
-                  int subsamp) throws Exception {
+                  int subsamp) {
     setBuf(yuvImage, width, pad, height, subsamp);
   }
 
@@ -210,20 +209,20 @@
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
   public void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
-                     int height, int subsamp) throws Exception {
+                     int height, int subsamp) {
     setBuf(planes, offsets, width, strides, height, subsamp, false);
   }
 
   private void setBuf(byte[][] planes, int[] offsets, int width, int strides[],
-                     int height, int subsamp, boolean alloc) throws Exception {
+                     int height, int subsamp, boolean alloc) {
     if ((planes == null && !alloc) || width < 1 || height < 1 || subsamp < 0 ||
         subsamp >= TJ.NUMSAMP)
-      throw new Exception("Invalid argument in YUVImage::setBuf()");
+      throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
 
     int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
     if (planes.length != nc || (offsets != null && offsets.length != nc) ||
         (strides != null && strides.length != nc))
-      throw new Exception("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
+      throw new IllegalArgumentException("YUVImage::setBuf(): planes, offsets, or strides array is the wrong size");
 
     if (offsets == null)
       offsets = new int[nc];
@@ -239,15 +238,15 @@
         strides[i] = pw;
       if (alloc) {
         if (strides[i] < pw)
-          throw new Exception("Stride must be >= plane width when allocating a new YUV image");
+          throw new IllegalArgumentException("Stride must be >= plane width when allocating a new YUV image");
         planes[i] = new byte[strides[i] * ph];
       }
       if (planes[i] == null || offsets[i] < 0)
-        throw new Exception("Invalid argument in YUVImage::setBuf()");
+        throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
       if (strides[i] < 0 && offsets[i] - planeSize + pw < 0)
-        throw new Exception("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
+        throw new IllegalArgumentException("Stride for plane " + i + " would cause memory to be accessed below plane boundary");
       if (planes[i].length < offsets[i] + planeSize)
-        throw new Exception("Image plane " + i + " is not large enough");
+        throw new IllegalArgumentException("Image plane " + i + " is not large enough");
     }
 
     yuvPlanes = planes;
@@ -279,13 +278,13 @@
    * image (one of {@link TJ#SAMP_444 TJ.SAMP_*})
    */
   public void setBuf(byte[] yuvImage, int width, int pad, int height,
-                     int subsamp) throws Exception {
+                     int subsamp) {
     if (yuvImage == null || width < 1 || pad < 1 || ((pad & (pad - 1)) != 0) ||
         height < 1 || subsamp < 0 || subsamp >= TJ.NUMSAMP)
-      throw new Exception("Invalid argument in YUVImage::setBuf()");
+      throw new IllegalArgumentException("Invalid argument in YUVImage::setBuf()");
     if (yuvImage.length < TJ.bufSizeYUV(width, pad, height, subsamp))
-      throw new Exception("YUV image buffer is not large enough");
-    
+      throw new IllegalArgumentException("YUV image buffer is not large enough");
+
     int nc = (subsamp == TJ.SAMP_GRAY ? 1 : 3);
     byte[][] planes = new byte[nc][];
     int[] strides = new int[nc];
@@ -311,9 +310,9 @@
    *
    * @return the width of the YUV image (or subregion)
    */
-  public int getWidth() throws Exception {
+  public int getWidth() {
     if (yuvWidth < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvWidth;
   }
 
@@ -322,9 +321,9 @@
    *
    * @return the height of the YUV image (or subregion)
    */
-  public int getHeight() throws Exception {
+  public int getHeight() {
     if (yuvHeight < 1)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvHeight;
   }
 
@@ -334,11 +333,11 @@
    *
    * @return the line padding used in the YUV image buffer
    */
-  public int getPad() throws Exception {
+  public int getPad() {
     if (yuvPlanes == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     if (yuvPad < 1 || ((yuvPad & (yuvPad - 1)) != 0))
-      throw new Exception("Image is not stored in a unified buffer");
+      throw new IllegalStateException("Image is not stored in a unified buffer");
     return yuvPad;
   }
 
@@ -347,9 +346,9 @@
    *
    * @return the number of bytes per line of each plane in the YUV image
    */
-  public int[] getStrides() throws Exception {
+  public int[] getStrides() {
     if (yuvStrides == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvStrides;
   }
 
@@ -360,9 +359,9 @@
    * @return the offsets (in bytes) of each plane within the planes of a larger
    * YUV image
    */
-  public int[] getOffsets() throws Exception {
+  public int[] getOffsets() {
     if (yuvOffsets == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvOffsets;
   }
 
@@ -372,9 +371,9 @@
    *
    * @return the level of chrominance subsampling used in the YUV image
    */
-  public int getSubsamp() throws Exception {
+  public int getSubsamp() {
     if (yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvSubsamp;
   }
 
@@ -384,9 +383,9 @@
    *
    * @return the YUV image planes
    */
-  public byte[][] getPlanes() throws Exception {
+  public byte[][] getPlanes() {
     if (yuvPlanes == null)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     return yuvPlanes;
   }
 
@@ -396,13 +395,13 @@
    *
    * @return the YUV image buffer
    */
-  public byte[] getBuf() throws Exception {
+  public byte[] getBuf() {
     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
     for (int i = 1; i < nc; i++) {
       if (yuvPlanes[i] != yuvPlanes[0])
-        throw new Exception("Image is not stored in a unified buffer");
+        throw new IllegalStateException("Image is not stored in a unified buffer");
     }
     return yuvPlanes[0];
   }
@@ -413,15 +412,15 @@
    *
    * @return the size (in bytes) of the YUV image buffer
    */
-  public int getSize() throws Exception {
+  public int getSize() {
     if (yuvPlanes == null || yuvSubsamp < 0 || yuvSubsamp >= TJ.NUMSAMP)
-      throw new Exception(NO_ASSOC_ERROR);
+      throw new IllegalStateException(NO_ASSOC_ERROR);
     int nc = (yuvSubsamp == TJ.SAMP_GRAY ? 1 : 3);
     if (yuvPad < 1)
-      throw new Exception("Image is not stored in a unified buffer");
+      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 Exception("Image is not stored in a unified buffer");
+        throw new IllegalStateException("Image is not stored in a unified buffer");
     }
     return TJ.bufSizeYUV(yuvWidth, yuvPad, yuvHeight, yuvSubsamp);
   }
@@ -438,4 +437,4 @@
   protected int yuvWidth = 0;
   protected int yuvHeight = 0;
   protected int yuvSubsamp = -1;
-};
+}
diff --git a/jdapistd.c b/jdapistd.c
index 3be527c..18f9f6c 100644
--- a/jdapistd.c
+++ b/jdapistd.c
@@ -4,7 +4,8 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2010, D. R. Commander.
+ * Copyright (C) 2010, 2015, D. R. Commander.
+ * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains application interface code for the decompression half
@@ -16,11 +17,10 @@
  * whole decompression library into a transcoder.
  */
 
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jpegcomp.h"
-
+#include "jdmainct.h"
+#include "jdcoefct.h"
+#include "jdsample.h"
+#include "jmemsys.h"
 
 /* Forward declarations */
 LOCAL(boolean) output_pass_setup (j_decompress_ptr cinfo);
@@ -179,6 +179,236 @@
 }
 
 
+/* 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)
+{
+}
+
+
+/*
+ * 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
+ * errors and to achieve the best possible performance.
+ */
+
+LOCAL(void)
+read_and_discard_scanlines (j_decompress_ptr cinfo, JDIMENSION num_lines)
+{
+  JDIMENSION n;
+  void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+                         JDIMENSION input_row, JSAMPARRAY output_buf,
+                         int num_rows);
+
+  color_convert = cinfo->cconvert->color_convert;
+  cinfo->cconvert->color_convert = noop_convert;
+
+  for (n = 0; n < num_lines; n++)
+    jpeg_read_scanlines(cinfo, NULL, 1);
+
+  cinfo->cconvert->color_convert = color_convert;
+}
+
+
+/*
+ * Called by jpeg_skip_scanlines().  This partially skips a decompress block by
+ * incrementing the rowgroup counter.
+ */
+
+LOCAL(void)
+increment_simple_rowgroup_ctr (j_decompress_ptr cinfo, JDIMENSION rows)
+{
+  JDIMENSION rows_left;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+
+  /* Increment the counter to the next row group after the skipped rows. */
+  main_ptr->rowgroup_ctr += rows / cinfo->max_v_samp_factor;
+
+  /* Partially skipping a row group would involve modifying the internal state
+   * of the upsampler, so read the remaining rows into a dummy buffer instead.
+   */
+  rows_left = rows % cinfo->max_v_samp_factor;
+  cinfo->output_scanline += rows - rows_left;
+
+  read_and_discard_scanlines(cinfo, rows_left);
+}
+
+/*
+ * Skips some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually skipped.  If skipping
+ * num_lines would move beyond the end of the image, then the actual number of
+ * lines remaining in the image is returned.  Otherwise, the return value will
+ * be equal to num_lines.
+ *
+ * Refer to libjpeg.txt for more information.
+ */
+
+GLOBAL(JDIMENSION)
+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;
+  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+  JDIMENSION i, x;
+  int y;
+  JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
+  JDIMENSION lines_to_skip, lines_to_read;
+
+  if (cinfo->global_state != DSTATE_SCANNING)
+    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+  /* Do not skip past the bottom of the image. */
+  if (cinfo->output_scanline + num_lines >= cinfo->output_height) {
+    cinfo->output_scanline = cinfo->output_height;
+    return cinfo->output_height - cinfo->output_scanline;
+  }
+
+  if (num_lines == 0)
+    return 0;
+
+  lines_per_iMCU_row = cinfo->_min_DCT_scaled_size * cinfo->max_v_samp_factor;
+  lines_left_in_iMCU_row =
+    (lines_per_iMCU_row - (cinfo->output_scanline % lines_per_iMCU_row)) %
+    lines_per_iMCU_row;
+  lines_after_iMCU_row = num_lines - lines_left_in_iMCU_row;
+
+  /* Skip the lines remaining in the current iMCU row.  When upsampling
+   * requires context rows, we need the previous and next rows in order to read
+   * the current row.  This adds some complexity.
+   */
+  if (cinfo->upsample->need_context_rows) {
+    /* If the skipped lines would not move us past the current iMCU row, we
+     * read the lines and ignore them.  There might be a faster way of doing
+     * this, but we are facing increasing complexity for diminishing returns.
+     * The increasing complexity would be a by-product of meddling with the
+     * state machine used to skip context rows.  Near the end of an iMCU row,
+     * the next iMCU row may have already been entropy-decoded.  In this unique
+     * case, we will read the next iMCU row if we cannot skip past it as well.
+     */
+    if ((num_lines < lines_left_in_iMCU_row + 1) ||
+        (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full &&
+         lines_after_iMCU_row < lines_per_iMCU_row + 1)) {
+      read_and_discard_scanlines(cinfo, num_lines);
+      return num_lines;
+    }
+
+    /* If the next iMCU row has already been entropy-decoded, make sure that
+     * we do not skip too far.
+     */
+    if (lines_left_in_iMCU_row <= 1 && main_ptr->buffer_full) {
+      cinfo->output_scanline += lines_left_in_iMCU_row + lines_per_iMCU_row;
+      lines_after_iMCU_row -= lines_per_iMCU_row;
+    } else {
+      cinfo->output_scanline += lines_left_in_iMCU_row;
+    }
+
+    /* If we have just completed the first block, adjust the buffer pointers */
+    if (main_ptr->iMCU_row_ctr == 0 ||
+        (main_ptr->iMCU_row_ctr == 1 && lines_left_in_iMCU_row > 2))
+      set_wraparound_pointers(cinfo);
+    main_ptr->buffer_full = FALSE;
+    main_ptr->rowgroup_ctr = 0;
+    main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
+    upsample->next_row_out = cinfo->max_v_samp_factor;
+    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
+  }
+
+  /* Skipping is much simpler when context rows are not required. */
+  else {
+    if (num_lines < lines_left_in_iMCU_row) {
+      increment_simple_rowgroup_ctr(cinfo, num_lines);
+      return num_lines;
+    } else {
+      cinfo->output_scanline += lines_left_in_iMCU_row;
+      main_ptr->buffer_full = FALSE;
+      main_ptr->rowgroup_ctr = 0;
+      upsample->next_row_out = cinfo->max_v_samp_factor;
+      upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
+    }
+  }
+
+  /* Calculate how many full iMCU rows we can skip. */
+  if (cinfo->upsample->need_context_rows)
+    lines_to_skip = ((lines_after_iMCU_row - 1) / lines_per_iMCU_row) *
+                    lines_per_iMCU_row;
+  else
+    lines_to_skip = (lines_after_iMCU_row / lines_per_iMCU_row) *
+                    lines_per_iMCU_row;
+  /* Calculate the number of lines that remain to be skipped after skipping all
+   * of the full iMCU rows that we can.  We will not read these lines unless we
+   * have to.
+   */
+  lines_to_read = lines_after_iMCU_row - lines_to_skip;
+
+  /* For images requiring multiple scans (progressive, non-interleaved, etc.),
+   * all of the entropy decoding occurs in jpeg_start_decompress(), assuming
+   * that the input data source is non-suspending.  This makes skipping easy.
+   */
+  if (cinfo->inputctl->has_multiple_scans) {
+    if (cinfo->upsample->need_context_rows) {
+      cinfo->output_scanline += lines_to_skip;
+      cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
+      main_ptr->iMCU_row_ctr += lines_after_iMCU_row / lines_per_iMCU_row;
+      /* It is complex to properly move to the middle of a context block, so
+       * read the remaining lines instead of skipping them.
+       */
+      read_and_discard_scanlines(cinfo, lines_to_read);
+    } else {
+      cinfo->output_scanline += lines_to_skip;
+      cinfo->output_iMCU_row += lines_to_skip / lines_per_iMCU_row;
+      increment_simple_rowgroup_ctr(cinfo, lines_to_read);
+    }
+    upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
+    return num_lines;
+  }
+
+  /* Skip the iMCU rows that we can safely skip. */
+  for (i = 0; i < lines_to_skip; i += lines_per_iMCU_row) {
+    for (y = 0; y < coef->MCU_rows_per_iMCU_row; y++) {
+      for (x = 0; x < cinfo->MCUs_per_row; x++) {
+        /* Calling decode_mcu() with a NULL pointer causes it to discard the
+         * decoded coefficients.  This is ~5% faster for large subsets, but
+         * it's tough to tell a difference for smaller images.
+         */
+        (*cinfo->entropy->decode_mcu) (cinfo, NULL);
+      }
+    }
+    cinfo->input_iMCU_row++;
+    cinfo->output_iMCU_row++;
+    if (cinfo->input_iMCU_row < cinfo->total_iMCU_rows)
+      start_iMCU_row(cinfo);
+    else
+      (*cinfo->inputctl->finish_input_pass) (cinfo);
+  }
+  cinfo->output_scanline += lines_to_skip;
+
+  if (cinfo->upsample->need_context_rows) {
+    /* Context-based upsampling keeps track of iMCU rows. */
+    main_ptr->iMCU_row_ctr += lines_to_skip / lines_per_iMCU_row;
+
+    /* It is complex to properly move to the middle of a context block, so
+     * read the remaining lines instead of skipping them.
+     */
+    read_and_discard_scanlines(cinfo, lines_to_read);
+  } else {
+    increment_simple_rowgroup_ctr(cinfo, lines_to_read);
+  }
+
+  /* Since skipping lines involves skipping the upsampling step, the value of
+   * "rows_to_go" will become invalid unless we set it here.  NOTE: This is a
+   * bit odd, since "rows_to_go" seems to be redundantly keeping track of
+   * output_scanline.
+   */
+  upsample->rows_to_go = cinfo->output_height - cinfo->output_scanline;
+
+  /* Always skip the requested number of lines. */
+  return num_lines;
+}
+
 /*
  * Alternate entry point to read raw data.
  * Processes exactly one iMCU row per call, unless suspended.
diff --git a/jdarith.c b/jdarith.c
index 885c8eb..0f9d912 100644
--- a/jdarith.c
+++ b/jdarith.c
@@ -3,8 +3,8 @@
  *
  * This file was part of the Independent JPEG Group's software:
  * Developed 1997-2009 by Guido Vollbeding.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2015, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains portable arithmetic entropy decoding routines for JPEG
@@ -516,7 +516,7 @@
   /* Outer loop handles each block in the MCU */
 
   for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
-    block = MCU_data[blkn];
+    block = MCU_data ? MCU_data[blkn] : NULL;
     ci = cinfo->MCU_membership[blkn];
     compptr = cinfo->cur_comp_info[ci];
 
@@ -563,7 +563,8 @@
       entropy->last_dc_val[ci] += v;
     }
 
-    (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
+    if (block)
+      (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
 
     /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
 
@@ -607,7 +608,8 @@
       while (m >>= 1)
         if (arith_decode(cinfo, st)) v |= m;
       v += 1; if (sign) v = -v;
-      (*block)[jpeg_natural_order[k]] = (JCOEF) v;
+      if (block)
+        (*block)[jpeg_natural_order[k]] = (JCOEF) v;
     }
   }
 
diff --git a/jdatasrc-tj.c b/jdatasrc-tj.c
index 09f9596..87e84b1 100644
--- a/jdatasrc-tj.c
+++ b/jdatasrc-tj.c
@@ -157,7 +157,7 @@
 
 GLOBAL(void)
 jpeg_mem_src_tj (j_decompress_ptr cinfo,
-              unsigned char * inbuffer, unsigned long insize)
+                 const unsigned char * inbuffer, unsigned long insize)
 {
   struct jpeg_source_mgr * src;
 
@@ -181,5 +181,5 @@
   src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
   src->term_source = term_source;
   src->bytes_in_buffer = (size_t) insize;
-  src->next_input_byte = (JOCTET *) inbuffer;
+  src->next_input_byte = (const JOCTET *) inbuffer;
 }
diff --git a/jdatasrc.c b/jdatasrc.c
index bf70422..22a09c8 100644
--- a/jdatasrc.c
+++ b/jdatasrc.c
@@ -254,7 +254,7 @@
 
 GLOBAL(void)
 jpeg_mem_src (j_decompress_ptr cinfo,
-              unsigned char * inbuffer, unsigned long insize)
+              const unsigned char * inbuffer, unsigned long insize)
 {
   struct jpeg_source_mgr * src;
 
@@ -278,6 +278,6 @@
   src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
   src->term_source = term_source;
   src->bytes_in_buffer = (size_t) insize;
-  src->next_input_byte = (JOCTET *) inbuffer;
+  src->next_input_byte = (const JOCTET *) inbuffer;
 }
 #endif
diff --git a/jdcoefct.c b/jdcoefct.c
index 199a628..17a97b1 100644
--- a/jdcoefct.c
+++ b/jdcoefct.c
@@ -4,6 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1994-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
+ * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
  * Copyright (C) 2010, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -16,53 +17,9 @@
  * Also, the input side (only) is used when reading a file for transcoding.
  */
 
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
+#include "jdcoefct.h"
 #include "jpegcomp.h"
 
-/* Block smoothing is only applicable for progressive JPEG, so: */
-#ifndef D_PROGRESSIVE_SUPPORTED
-#undef BLOCK_SMOOTHING_SUPPORTED
-#endif
-
-/* 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 */
-  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. */
-
-  /* In single-pass modes, it's sufficient to buffer just one MCU.
-   * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
-   * and let the entropy decoder write into that workspace each time.
-   * In multi-pass modes, this array points to the current MCU's blocks
-   * within the virtual arrays; it is used only by the input side.
-   */
-  JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
-
-  /* Temporary workspace for one MCU */
-  JCOEF * workspace;
-
-#ifdef D_MULTISCAN_FILES_SUPPORTED
-  /* In multi-pass modes, we need a virtual block array for each component. */
-  jvirt_barray_ptr whole_image[MAX_COMPONENTS];
-#endif
-
-#ifdef BLOCK_SMOOTHING_SUPPORTED
-  /* When doing block smoothing, we latch coefficient Al values here */
-  int * coef_bits_latch;
-#define SAVED_COEFS  6          /* we save coef_bits[0..5] */
-#endif
-} my_coef_controller;
-
-typedef my_coef_controller * my_coef_ptr;
 
 /* Forward declarations */
 METHODDEF(int) decompress_onepass
@@ -78,30 +35,6 @@
 #endif
 
 
-LOCAL(void)
-start_iMCU_row (j_decompress_ptr cinfo)
-/* Reset within-iMCU-row counters for a new row (input side) */
-{
-  my_coef_ptr coef = (my_coef_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) {
-    coef->MCU_rows_per_iMCU_row = 1;
-  } else {
-    if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
-      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
-    else
-      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
-  }
-
-  coef->MCU_ctr = 0;
-  coef->MCU_vert_offset = 0;
-}
-
-
 /*
  * Initialize for an input processing pass.
  */
diff --git a/jdcoefct.h b/jdcoefct.h
new file mode 100644
index 0000000..2f7bbe5
--- /dev/null
+++ b/jdcoefct.h
@@ -0,0 +1,82 @@
+/*
+ * jdcoefct.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Block smoothing is only applicable for progressive JPEG, so: */
+#ifndef D_PROGRESSIVE_SUPPORTED
+#undef BLOCK_SMOOTHING_SUPPORTED
+#endif
+
+
+/* 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 */
+  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. */
+
+  /* In single-pass modes, it's sufficient to buffer just one MCU.
+   * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+   * and let the entropy decoder write into that workspace each time.
+   * In multi-pass modes, this array points to the current MCU's blocks
+   * within the virtual arrays; it is used only by the input side.
+   */
+  JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
+
+  /* Temporary workspace for one MCU */
+  JCOEF * workspace;
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+  /* In multi-pass modes, we need a virtual block array for each component. */
+  jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+#endif
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+  /* When doing block smoothing, we latch coefficient Al values here */
+  int * coef_bits_latch;
+#define SAVED_COEFS  6          /* we save coef_bits[0..5] */
+#endif
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+LOCAL(void)
+start_iMCU_row (j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+  my_coef_ptr coef = (my_coef_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) {
+    coef->MCU_rows_per_iMCU_row = 1;
+  } else {
+    if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+    else
+      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+  }
+
+  coef->MCU_ctr = 0;
+  coef->MCU_vert_offset = 0;
+}
diff --git a/jdhuff.c b/jdhuff.c
index aacc036..e6bb081 100644
--- a/jdhuff.c
+++ b/jdhuff.c
@@ -4,7 +4,7 @@
  * This file was part of the Independent JPEG Group's software:
  * Copyright (C) 1991-1997, Thomas G. Lane.
  * libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, D. R. Commander.
+ * Copyright (C) 2009-2011, 2015, D. R. Commander.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains Huffman entropy decoding routines.
@@ -564,7 +564,7 @@
   ASSIGN_STATE(state, entropy->saved);
 
   for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
-    JBLOCKROW block = MCU_data[blkn];
+    JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
     d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
     d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
     register int s, k, r;
@@ -584,11 +584,13 @@
       int ci = cinfo->MCU_membership[blkn];
       s += state.last_dc_val[ci];
       state.last_dc_val[ci] = s;
-      /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
-      (*block)[0] = (JCOEF) s;
+      if (block) {
+        /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */
+        (*block)[0] = (JCOEF) s;
+      }
     }
 
-    if (entropy->ac_needed[blkn]) {
+    if (entropy->ac_needed[blkn] && block) {
 
       /* Section F.2.2.2: decode the AC coefficients */
       /* Since zeroes are skipped, output area must be cleared beforehand */
@@ -661,7 +663,7 @@
   ASSIGN_STATE(state, entropy->saved);
 
   for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
-    JBLOCKROW block = MCU_data[blkn];
+    JBLOCKROW block = MCU_data ? MCU_data[blkn] : NULL;
     d_derived_tbl * dctbl = entropy->dc_cur_tbls[blkn];
     d_derived_tbl * actbl = entropy->ac_cur_tbls[blkn];
     register int s, k, r, l;
@@ -677,10 +679,11 @@
       int ci = cinfo->MCU_membership[blkn];
       s += state.last_dc_val[ci];
       state.last_dc_val[ci] = s;
-      (*block)[0] = (JCOEF) s;
+      if (block)
+        (*block)[0] = (JCOEF) s;
     }
 
-    if (entropy->ac_needed[blkn]) {
+    if (entropy->ac_needed[blkn] && block) {
 
       for (k = 1; k < DCTSIZE2; k++) {
         HUFF_DECODE_FAST(s, l, actbl);
diff --git a/jdmainct.c b/jdmainct.c
index 7f7bd33..e4ba1c4 100644
--- a/jdmainct.c
+++ b/jdmainct.c
@@ -15,10 +15,7 @@
  * supplies the equivalent of the main buffer in that case.
  */
 
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jdmainct.h"
 
 
 /*
@@ -112,36 +109,6 @@
  */
 
 
-/* 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];
-
-  boolean buffer_full;          /* Have we gotten an iMCU row from decoder? */
-  JDIMENSION rowgroup_ctr;      /* counts row groups output to postprocessor */
-
-  /* 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 */
-
-  int whichptr;                 /* indicates which pointer set is now in use */
-  int context_state;            /* process_data state machine status */
-  JDIMENSION rowgroups_avail;   /* row groups available to postprocessor */
-  JDIMENSION iMCU_row_ctr;      /* counts iMCU rows to detect image top/bot */
-} my_main_controller;
-
-typedef my_main_controller * my_main_ptr;
-
-/* context_state values: */
-#define CTX_PREPARE_FOR_IMCU    0       /* need to prepare for MCU row */
-#define CTX_PROCESS_IMCU        1       /* feeding iMCU to postprocessor */
-#define CTX_POSTPONED_ROW       2       /* feeding postponed row group */
-
-
 /* Forward declarations */
 METHODDEF(void) process_data_simple_main
         (j_decompress_ptr cinfo, JSAMPARRAY output_buf,
@@ -238,34 +205,6 @@
 
 
 LOCAL(void)
-set_wraparound_pointers (j_decompress_ptr cinfo)
-/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
- * This changes the pointer list state from top-of-image to the normal state.
- */
-{
-  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
-  int ci, i, rgroup;
-  int M = cinfo->_min_DCT_scaled_size;
-  jpeg_component_info *compptr;
-  JSAMPARRAY xbuf0, xbuf1;
-
-  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
-       ci++, compptr++) {
-    rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
-      cinfo->_min_DCT_scaled_size; /* height of a row group of component */
-    xbuf0 = main_ptr->xbuffer[0][ci];
-    xbuf1 = main_ptr->xbuffer[1][ci];
-    for (i = 0; i < rgroup; i++) {
-      xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
-      xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
-      xbuf0[rgroup*(M+2) + i] = xbuf0[i];
-      xbuf1[rgroup*(M+2) + i] = xbuf1[i];
-    }
-  }
-}
-
-
-LOCAL(void)
 set_bottom_pointers (j_decompress_ptr cinfo)
 /* Change the pointer lists to duplicate the last sample row at the bottom
  * of the image.  whichptr indicates which xbuffer holds the final iMCU row.
diff --git a/jdmainct.h b/jdmainct.h
new file mode 100644
index 0000000..37ab27d
--- /dev/null
+++ b/jdmainct.h
@@ -0,0 +1,71 @@
+/*
+ * jdmainct.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jpegcomp.h"
+
+
+/* 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];
+
+  boolean buffer_full;          /* Have we gotten an iMCU row from decoder? */
+  JDIMENSION rowgroup_ctr;      /* counts row groups output to postprocessor */
+
+  /* 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 */
+
+  int whichptr;                 /* indicates which pointer set is now in use */
+  int context_state;            /* process_data state machine status */
+  JDIMENSION rowgroups_avail;   /* row groups available to postprocessor */
+  JDIMENSION iMCU_row_ctr;      /* counts iMCU rows to detect image top/bot */
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+
+/* context_state values: */
+#define CTX_PREPARE_FOR_IMCU    0       /* need to prepare for MCU row */
+#define CTX_PROCESS_IMCU        1       /* feeding iMCU to postprocessor */
+#define CTX_POSTPONED_ROW       2       /* feeding postponed row group */
+
+
+LOCAL(void)
+set_wraparound_pointers (j_decompress_ptr cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
+  int ci, i, rgroup;
+  int M = cinfo->_min_DCT_scaled_size;
+  jpeg_component_info *compptr;
+  JSAMPARRAY xbuf0, xbuf1;
+
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
+      cinfo->_min_DCT_scaled_size; /* height of a row group of component */
+    xbuf0 = main_ptr->xbuffer[0][ci];
+    xbuf1 = main_ptr->xbuffer[1][ci];
+    for (i = 0; i < rgroup; i++) {
+      xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+      xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+      xbuf0[rgroup*(M+2) + i] = xbuf0[i];
+      xbuf1[rgroup*(M+2) + i] = xbuf1[i];
+    }
+  }
+}
diff --git a/jdsample.c b/jdsample.c
index 2752966..5738c2f 100644
--- a/jdsample.c
+++ b/jdsample.c
@@ -22,51 +22,11 @@
  *   Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
  */
 
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
+#include "jdsample.h"
 #include "jsimd.h"
 #include "jpegcomp.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);
-
-/* Private subobject */
-
-typedef struct {
-  struct jpeg_upsampler pub;    /* public fields */
-
-  /* Color conversion buffer.  When using separate upsampling and color
-   * conversion steps, this buffer holds one upsampled row group until it
-   * has been color converted and output.
-   * Note: we do not allocate any storage for component(s) which are full-size,
-   * 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];
-
-  /* Per-component upsampling method pointers */
-  upsample1_ptr methods[MAX_COMPONENTS];
-
-  int next_row_out;             /* counts rows emitted from color_buf */
-  JDIMENSION rows_to_go;        /* counts rows remaining in image */
-
-  /* Height of an input row group for each component. */
-  int rowgroup_height[MAX_COMPONENTS];
-
-  /* These arrays save pixel expansion factors so that int_expand need not
-   * recompute them each time.  They are unused for other upsampling methods.
-   */
-  UINT8 h_expand[MAX_COMPONENTS];
-  UINT8 v_expand[MAX_COMPONENTS];
-} my_upsampler;
-
-typedef my_upsampler * my_upsample_ptr;
-
 
 /*
  * Initialize for an upsampling pass.
diff --git a/jdsample.h b/jdsample.h
new file mode 100644
index 0000000..5226f26
--- /dev/null
+++ b/jdsample.h
@@ -0,0 +1,50 @@
+/*
+ * jdsample.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.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);
+
+/* Private subobject */
+
+typedef struct {
+  struct jpeg_upsampler pub;    /* public fields */
+
+  /* Color conversion buffer.  When using separate upsampling and color
+   * conversion steps, this buffer holds one upsampled row group until it
+   * has been color converted and output.
+   * Note: we do not allocate any storage for component(s) which are full-size,
+   * 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];
+
+  /* Per-component upsampling method pointers */
+  upsample1_ptr methods[MAX_COMPONENTS];
+
+  int next_row_out;             /* counts rows emitted from color_buf */
+  JDIMENSION rows_to_go;        /* counts rows remaining in image */
+
+  /* Height of an input row group for each component. */
+  int rowgroup_height[MAX_COMPONENTS];
+
+  /* These arrays save pixel expansion factors so that int_expand need not
+   * recompute them each time.  They are unused for other upsampling methods.
+   */
+  UINT8 h_expand[MAX_COMPONENTS];
+  UINT8 v_expand[MAX_COMPONENTS];
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
diff --git a/jpeglib.h b/jpeglib.h
index 9615c5d..aec9180 100644
--- a/jpeglib.h
+++ b/jpeglib.h
@@ -6,6 +6,7 @@
  * Modified 2002-2009 by Guido Vollbeding.
  * libjpeg-turbo Modifications:
  * Copyright (C) 2009-2011, 2013-2014, D. R. Commander.
+ * Copyright (C) 2015, Google, Inc.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file defines the application interface for the JPEG library.
@@ -918,7 +919,8 @@
 /* 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, unsigned char * inbuffer,
+EXTERN(void) jpeg_mem_src (j_decompress_ptr cinfo,
+                           const unsigned char * inbuffer,
                            unsigned long insize);
 #endif
 
@@ -990,6 +992,8 @@
 EXTERN(JDIMENSION) jpeg_read_scanlines (j_decompress_ptr cinfo,
                                         JSAMPARRAY scanlines,
                                         JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg_skip_scanlines (j_decompress_ptr cinfo,
+                                        JDIMENSION num_lines);
 EXTERN(boolean) jpeg_finish_decompress (j_decompress_ptr cinfo);
 
 /* Replaces jpeg_read_scanlines when reading raw downsampled data. */
diff --git a/libjpeg.txt b/libjpeg.txt
index 7dbb354..52b6d8b 100644
--- a/libjpeg.txt
+++ b/libjpeg.txt
@@ -3,7 +3,8 @@
 This file was part of the Independent JPEG Group's software:
 Copyright (C) 1994-2011, Thomas G. Lane, Guido Vollbeding.
 libjpeg-turbo Modifications:
-Copyright (C) 2010, 2014, D. R. Commander.
+Copyright (C) 2010, 2014, 2015, D. R. Commander.
+Copyright (C) 2015, Google, Inc.
 For conditions of distribution and use, see the accompanying README file.
 
 
@@ -729,6 +730,49 @@
 The previous discussion of aborting compression cycles applies here too.
 
 
+Skipping rows when decompressing
+--------------------------------
+
+jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines);
+
+This function provides application programmers with the ability to skip over
+multiple rows in the JPEG image, thus decoding only a subset of the image data.
+This is convenient for performance-critical applications that wish to view only
+a portion of a large JPEG image without decompressing the whole thing.  It it
+also useful in memory-constrained environments (such as on mobile devices.)
+
+Suspending data sources are not supported by this function.  Calling
+jpeg_skip_scanlines() with a suspending data source will result in undefined
+behavior.
+
+jpeg_skip_scanlines() will not allow skipping past the bottom of the image.  If
+the value of num_lines is large enough to skip past the bottom of the image,
+then the function will skip to the end of the image instead.
+
+If the value of num_lines is valid, then jpeg_skip_scanlines() will always
+skip all of the input rows requested.  There is no need to inspect the return
+value of the function in that case.
+
+Best results will be achieved by calling jpeg_skip_scanlines() for large chunks
+of rows.  The function should be viewed as a way to quickly jump to a
+particular vertical offset in the JPEG image in order to decode a subset of the
+image.  Used in this manner, it will provide significant performance
+improvements.
+
+Calling jpeg_skip_scanlines() for small values of num_lines has several
+potential drawbacks:
+    1) JPEG decompression occurs in blocks, so if jpeg_skip_scanlines() is
+       called from the middle of a decompression block, then it is likely that
+       much of the decompression work has already been done for the first
+       couple of rows that need to be skipped.
+    2) When this function returns, it must leave the decompressor in a state
+       such that it is ready to read the next line.  This may involve
+       decompressing a block that must be partially skipped.
+These issues are especially tricky for cases in which upsampling requires
+context rows.  In the worst case, jpeg_skip_scanlines() will perform similarly
+to jpeg_read_scanlines() (since it will actually call jpeg_read_scanlines().)
+
+
 Mechanics of usage: include files, linking, etc
 -----------------------------------------------
 
diff --git a/release/ReadMe.txt b/release/ReadMe.txt
index b9f6ca5..2f00e8a 100644
--- a/release/ReadMe.txt
+++ b/release/ReadMe.txt
@@ -1,4 +1,4 @@
-libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2, NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64, and ARM systems.  On such systems, libjpeg-turbo is generally 2-4x as fast as libjpeg, all else being equal.  On other types of systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by virtue of its highly-optimized Huffman coding routines.  In many cases, the performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
+libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2, NEON, AltiVec) to accelerate baseline JPEG compression and decompression on x86, x86-64, ARM, and PowerPC systems.  On such systems, libjpeg-turbo is generally 2-4x as fast as libjpeg, all else being equal.  On other types of systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by virtue of its highly-optimized Huffman coding routines.  In many cases, the performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
 
 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.
 
diff --git a/release/deb-control.tmpl b/release/deb-control.tmpl
index 510b1d6..1a6242b 100644
--- a/release/deb-control.tmpl
+++ b/release/deb-control.tmpl
@@ -9,11 +9,11 @@
 Installed-Size: {__SIZE}
 Description: A SIMD-accelerated JPEG codec that provides both the libjpeg and TurboJPEG APIs
  libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
- NEON) to accelerate baseline JPEG compression and decompression on x86,
- x86-64, and ARM systems.  On such systems, libjpeg-turbo is generally 2-4x as
- fast as libjpeg, all else being equal.  On other types of systems,
- libjpeg-turbo can still outperform libjpeg by a significant amount, by virtue
- of its highly-optimized Huffman coding routines.  In many cases, the
+ NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
+ x86, x86-64, ARM, and PowerPC systems.  On such systems, libjpeg-turbo is
+ generally 2-4x as fast as libjpeg, all else being equal.  On other types of
+ systems, libjpeg-turbo can still outperform libjpeg by a significant amount,
+ by virtue of its highly-optimized Huffman coding routines.  In many cases, the
  performance of libjpeg-turbo rivals that of proprietary high-speed JPEG
  codecs.
  .
diff --git a/release/libjpeg-turbo.spec.in b/release/libjpeg-turbo.spec.in
index 23793cf..03d75d1 100644
--- a/release/libjpeg-turbo.spec.in
+++ b/release/libjpeg-turbo.spec.in
@@ -44,12 +44,12 @@
 
 %description
 libjpeg-turbo is a JPEG image codec that uses SIMD instructions (MMX, SSE2,
-NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64,
-and ARM systems.  On such systems, libjpeg-turbo is generally 2-4x as fast as
-libjpeg, all else being equal.  On other types of systems, libjpeg-turbo can
-still outperform libjpeg by a significant amount, by virtue of its
-highly-optimized Huffman coding routines.  In many cases, the performance of
-libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
+NEON, AltiVec) to accelerate baseline JPEG compression and decompression on
+x86, x86-64, ARM, and PowerPC systems.  On such systems, libjpeg-turbo is
+generally 2-4x as fast as libjpeg, all else being equal.  On other types of
+systems, libjpeg-turbo can still outperform libjpeg by a significant amount, by
+virtue of its highly-optimized Huffman coding routines.  In many cases, the
+performance of libjpeg-turbo rivals that of proprietary high-speed JPEG codecs.
 
 libjpeg-turbo implements both the traditional libjpeg API as well as the less
 powerful but more straightforward TurboJPEG API.  libjpeg-turbo also features
diff --git a/simd/Makefile.am b/simd/Makefile.am
index 3029f1c..ebb9ec6 100644
--- a/simd/Makefile.am
+++ b/simd/Makefile.am
@@ -6,7 +6,8 @@
 	jccolext-mmx.asm   jcgryext-mmx.asm   jdcolext-mmx.asm   jdmrgext-mmx.asm \
 	jccolext-sse2.asm  jcgryext-sse2.asm  jdcolext-sse2.asm  jdmrgext-sse2.asm \
 	jccolext-sse2-64.asm  jcgryext-sse2-64.asm  jdcolext-sse2-64.asm \
-	jdmrgext-sse2-64.asm
+	jdmrgext-sse2-64.asm  jccolext-altivec.c    jcgryext-altivec.c \
+	jdcolext-altivec.c    jdmrgext-altivec.c
 
 if SIMD_X86_64
 
@@ -70,6 +71,23 @@
 
 endif
 
+if SIMD_POWERPC
+
+libsimd_la_SOURCES = jsimd_powerpc.c jsimd_altivec.h jcsample.h \
+	jccolor-altivec.c     jcgray-altivec.c      jcsample-altivec.c \
+	jdcolor-altivec.c     jdmerge-altivec.c     jdsample-altivec.c \
+	jfdctfst-altivec.c    jfdctint-altivec.c \
+	jidctfst-altivec.c    jidctint-altivec.c \
+	jquanti-altivec.c
+libsimd_la_CFLAGS = -maltivec
+
+jccolor-altivec.lo:  jccolext-altivec.c
+jcgray-altivec.lo:   jcgryext-altivec.c
+jdcolor-altivec.lo:  jdcolext-altivec.c
+jdmerge-altivec.lo:  jdmrgext-altivec.c
+
+endif
+
 AM_CPPFLAGS = -I$(top_srcdir)
 
 .asm.lo:
diff --git a/simd/jccolext-altivec.c b/simd/jccolext-altivec.c
new file mode 100644
index 0000000..403aa96
--- /dev/null
+++ b/simd/jccolext-altivec.c
@@ -0,0 +1,267 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, D. R. Commander.
+ * Copyright (C) 2014, Jay Foad.
+ * 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
+ * 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.
+ */
+
+/* This file is included by jccolor-altivec.c */
+
+
+void jsimd_rgb_ycc_convert_altivec (JDIMENSION img_width, JSAMPARRAY input_buf,
+                                    JSAMPIMAGE output_buf,
+                                    JDIMENSION output_row, int num_rows)
+{
+  JSAMPROW inptr, outptr0, outptr1, outptr2;
+  int pitch = img_width * RGB_PIXELSIZE, num_cols;
+#if __BIG_ENDIAN__
+  int offset;
+#endif
+  unsigned char __attribute__((aligned(16))) tmpbuf[RGB_PIXELSIZE * 16];
+
+  __vector unsigned char rgb0, rgb1 = {0}, rgb2 = {0},
+    rgbg0, rgbg1, rgbg2, rgbg3, y, cb, cr;
+#if __BIG_ENDIAN__ || RGB_PIXELSIZE == 4
+  __vector unsigned char rgb3 = {0};
+#endif
+#if __BIG_ENDIAN__ && RGB_PIXELSIZE == 4
+  __vector unsigned char rgb4 = {0};
+#endif
+  __vector short rg0, rg1, rg2, rg3, bg0, bg1, bg2, bg3;
+  __vector unsigned short yl, yh, crl, crh, cbl, cbh;
+  __vector int y0, y1, y2, y3, cr0, cr1, cr2, cr3, cb0, cb1, cb2, cb3;
+
+  /* Constants */
+  __vector short pw_f0299_f0337 = { __4X2(F_0_299, F_0_337) },
+    pw_f0114_f0250 = { __4X2(F_0_114, F_0_250) },
+    pw_mf016_mf033 = { __4X2(-F_0_168, -F_0_331) },
+    pw_mf008_mf041 = { __4X2(-F_0_081, -F_0_418) };
+  __vector unsigned short pw_f050_f000 = { __4X2(F_0_500, 0) };
+  __vector int pd_onehalf = { __4X(ONE_HALF) },
+    pd_onehalfm1_cj = { __4X(ONE_HALF - 1 + (CENTERJSAMPLE << SCALEBITS)) };
+  __vector unsigned char pb_zero = { __16X(0) },
+#if __BIG_ENDIAN__
+    shift_pack_index = {0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29};
+#else
+    shift_pack_index = {2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31};
+#endif
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr0 = output_buf[0][output_row];
+    outptr1 = output_buf[1][output_row];
+    outptr2 = output_buf[2][output_row];
+    output_row++;
+
+    for (num_cols = pitch; num_cols > 0;
+         num_cols -= RGB_PIXELSIZE * 16, inptr += RGB_PIXELSIZE * 16,
+         outptr0 += 16, outptr1 += 16, outptr2 += 16) {
+
+#if __BIG_ENDIAN__
+      /* Load 16 pixels == 48 or 64 bytes */
+      offset = (size_t)inptr & 15;
+      if (offset) {
+        __vector unsigned char unaligned_shift_index;
+        int bytes = num_cols + offset;
+
+        if (bytes < (RGB_PIXELSIZE + 1) * 16 && (bytes & 15)) {
+          /* Slow path to prevent buffer overread.  Since there is no way to
+           * read a partial AltiVec register, overread would occur on the last
+           * chunk of the last image row if the right edge is not on a 16-byte
+           * boundary.  It could also occur on other rows if the bytes per row
+           * is low enough.  Since we can't determine whether we're on the last
+           * image row, we have to assume every row is the last.
+           */
+          memcpy(tmpbuf, inptr, min(num_cols, RGB_PIXELSIZE * 16));
+          rgb0 = vec_ld(0, tmpbuf);
+          rgb1 = vec_ld(16, tmpbuf);
+          rgb2 = vec_ld(32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          rgb3 = vec_ld(48, tmpbuf);
+#endif
+        } else {
+          /* Fast path */
+          rgb0 = vec_ld(0, inptr);
+          if (bytes > 16)
+            rgb1 = vec_ld(16, inptr);
+          if (bytes > 32)
+            rgb2 = vec_ld(32, inptr);
+          if (bytes > 48)
+            rgb3 = vec_ld(48, inptr);
+#if RGB_PIXELSIZE == 4
+          if (bytes > 64)
+            rgb4 = vec_ld(64, inptr);
+#endif
+          unaligned_shift_index = vec_lvsl(0, inptr);
+          rgb0 = vec_perm(rgb0, rgb1, unaligned_shift_index);
+          rgb1 = vec_perm(rgb1, rgb2, unaligned_shift_index);
+          rgb2 = vec_perm(rgb2, rgb3, unaligned_shift_index);
+#if RGB_PIXELSIZE == 4
+          rgb3 = vec_perm(rgb3, rgb4, unaligned_shift_index);
+#endif
+        }
+      } else {
+#endif /* __BIG_ENDIAN__ */
+        if (num_cols < RGB_PIXELSIZE * 16 && (num_cols & 15)) {
+          /* Slow path */
+          memcpy(tmpbuf, inptr, min(num_cols, RGB_PIXELSIZE * 16));
+          rgb0 = VEC_LD(0, tmpbuf);
+          rgb1 = VEC_LD(16, tmpbuf);
+          rgb2 = VEC_LD(32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          rgb3 = VEC_LD(48, tmpbuf);
+#endif
+        } else {
+          /* Fast path */
+          rgb0 = VEC_LD(0, inptr);
+          if (num_cols > 16)
+            rgb1 = VEC_LD(16, inptr);
+          if (num_cols > 32)
+            rgb2 = VEC_LD(32, inptr);
+#if RGB_PIXELSIZE == 4
+          if (num_cols > 48)
+            rgb3 = VEC_LD(48, inptr);
+#endif
+        }
+#if __BIG_ENDIAN__
+      }
+#endif
+
+#if RGB_PIXELSIZE == 3
+      /* rgb0 = R0 G0 B0 R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4 R5
+       * rgb1 = G5 B5 R6 G6 B6 R7 G7 B7 R8 G8 B8 R9 G9 B9 Ra Ga
+       * rgb2 = Ba Rb Gb Bb Rc Gc Bc Rd Gd Bd Re Ge Be Rf Gf Bf
+       *
+       * rgbg0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 G0 B1 G1 B2 G2 B3 G3
+       * rgbg1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 G4 B5 G5 B6 G6 B7 G7
+       * rgbg2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 G8 B9 G9 Ba Ga Bb Gb
+       * rgbg3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Gc Bd Gd Be Ge Bf Gf
+       */
+      rgbg0 = vec_perm(rgb0, rgb0, (__vector unsigned char)RGBG_INDEX0);
+      rgbg1 = vec_perm(rgb0, rgb1, (__vector unsigned char)RGBG_INDEX1);
+      rgbg2 = vec_perm(rgb1, rgb2, (__vector unsigned char)RGBG_INDEX2);
+      rgbg3 = vec_perm(rgb2, rgb2, (__vector unsigned char)RGBG_INDEX3);
+#else
+      /* rgb0 = R0 G0 B0 X0 R1 G1 B1 X1 R2 G2 B2 X2 R3 G3 B3 X3
+       * rgb1 = R4 G4 B4 X4 R5 G5 B5 X5 R6 G6 B6 X6 R7 G7 B7 X7
+       * rgb2 = R8 G8 B8 X8 R9 G9 B9 X9 Ra Ga Ba Xa Rb Gb Bb Xb
+       * rgb3 = Rc Gc Bc Xc Rd Gd Bd Xd Re Ge Be Xe Rf Gf Bf Xf
+       *
+       * rgbg0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 G0 B1 G1 B2 G2 B3 G3
+       * rgbg1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 G4 B5 G5 B6 G6 B7 G7
+       * rgbg2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 G8 B9 G9 Ba Ga Bb Gb
+       * rgbg3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Gc Bd Gd Be Ge Bf Gf
+       */
+      rgbg0 = vec_perm(rgb0, rgb0, (__vector unsigned char)RGBG_INDEX);
+      rgbg1 = vec_perm(rgb1, rgb1, (__vector unsigned char)RGBG_INDEX);
+      rgbg2 = vec_perm(rgb2, rgb2, (__vector unsigned char)RGBG_INDEX);
+      rgbg3 = vec_perm(rgb3, rgb3, (__vector unsigned char)RGBG_INDEX);
+#endif
+
+      /* rg0 = R0 G0 R1 G1 R2 G2 R3 G3
+       * bg0 = B0 G0 B1 G1 B2 G2 B3 G3
+       * ...
+       *
+       * NOTE: We have to use vec_merge*() here because vec_unpack*() doesn't
+       * support unsigned vectors.
+       */
+      rg0 = (__vector signed short)VEC_UNPACKHU(rgbg0);
+      bg0 = (__vector signed short)VEC_UNPACKLU(rgbg0);
+      rg1 = (__vector signed short)VEC_UNPACKHU(rgbg1);
+      bg1 = (__vector signed short)VEC_UNPACKLU(rgbg1);
+      rg2 = (__vector signed short)VEC_UNPACKHU(rgbg2);
+      bg2 = (__vector signed short)VEC_UNPACKLU(rgbg2);
+      rg3 = (__vector signed short)VEC_UNPACKHU(rgbg3);
+      bg3 = (__vector signed short)VEC_UNPACKLU(rgbg3);
+
+      /* (Original)
+       * 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
+       *
+       * (This implementation)
+       * Y  =  0.29900 * R + 0.33700 * G + 0.11400 * B + 0.25000 * G
+       * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
+       * Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+       */
+
+      /* Calculate Y values */
+
+      y0 = vec_msums(rg0, pw_f0299_f0337, pd_onehalf);
+      y1 = vec_msums(rg1, pw_f0299_f0337, pd_onehalf);
+      y2 = vec_msums(rg2, pw_f0299_f0337, pd_onehalf);
+      y3 = vec_msums(rg3, pw_f0299_f0337, pd_onehalf);
+      y0 = vec_msums(bg0, pw_f0114_f0250, y0);
+      y1 = vec_msums(bg1, pw_f0114_f0250, y1);
+      y2 = vec_msums(bg2, pw_f0114_f0250, y2);
+      y3 = vec_msums(bg3, pw_f0114_f0250, y3);
+      /* Clever way to avoid 4 shifts + 2 packs.  This packs the high word from
+       * each dword into a new 16-bit vector, which is the equivalent of
+       * descaling the 32-bit results (right-shifting by 16 bits) and then
+       * packing them.
+       */
+      yl = vec_perm((__vector unsigned short)y0, (__vector unsigned short)y1,
+                    shift_pack_index);
+      yh = vec_perm((__vector unsigned short)y2, (__vector unsigned short)y3,
+                    shift_pack_index);
+      y = vec_pack(yl, yh);
+      vec_st(y, 0, outptr0);
+
+      /* Calculate Cb values */
+      cb0 = vec_msums(rg0, pw_mf016_mf033, pd_onehalfm1_cj);
+      cb1 = vec_msums(rg1, pw_mf016_mf033, pd_onehalfm1_cj);
+      cb2 = vec_msums(rg2, pw_mf016_mf033, pd_onehalfm1_cj);
+      cb3 = vec_msums(rg3, pw_mf016_mf033, pd_onehalfm1_cj);
+      cb0 = (__vector int)vec_msum((__vector unsigned short)bg0, pw_f050_f000,
+                                   (__vector unsigned int)cb0);
+      cb1 = (__vector int)vec_msum((__vector unsigned short)bg1, pw_f050_f000,
+                                   (__vector unsigned int)cb1);
+      cb2 = (__vector int)vec_msum((__vector unsigned short)bg2, pw_f050_f000,
+                                   (__vector unsigned int)cb2);
+      cb3 = (__vector int)vec_msum((__vector unsigned short)bg3, pw_f050_f000,
+                                   (__vector unsigned int)cb3);
+      cbl = vec_perm((__vector unsigned short)cb0,
+                     (__vector unsigned short)cb1, shift_pack_index);
+      cbh = vec_perm((__vector unsigned short)cb2,
+                     (__vector unsigned short)cb3, shift_pack_index);
+      cb = vec_pack(cbl, cbh);
+      vec_st(cb, 0, outptr1);
+
+      /* Calculate Cr values */
+      cr0 = vec_msums(bg0, pw_mf008_mf041, pd_onehalfm1_cj);
+      cr1 = vec_msums(bg1, pw_mf008_mf041, pd_onehalfm1_cj);
+      cr2 = vec_msums(bg2, pw_mf008_mf041, pd_onehalfm1_cj);
+      cr3 = vec_msums(bg3, pw_mf008_mf041, pd_onehalfm1_cj);
+      cr0 = (__vector int)vec_msum((__vector unsigned short)rg0, pw_f050_f000,
+                                   (__vector unsigned int)cr0);
+      cr1 = (__vector int)vec_msum((__vector unsigned short)rg1, pw_f050_f000,
+                                   (__vector unsigned int)cr1);
+      cr2 = (__vector int)vec_msum((__vector unsigned short)rg2, pw_f050_f000,
+                                   (__vector unsigned int)cr2);
+      cr3 = (__vector int)vec_msum((__vector unsigned short)rg3, pw_f050_f000,
+                                   (__vector unsigned int)cr3);
+      crl = vec_perm((__vector unsigned short)cr0,
+                     (__vector unsigned short)cr1, shift_pack_index);
+      crh = vec_perm((__vector unsigned short)cr2,
+                     (__vector unsigned short)cr3, shift_pack_index);
+      cr = vec_pack(crl, crh);
+      vec_st(cr, 0, outptr2);
+    }
+  }
+}
diff --git a/simd/jccolor-altivec.c b/simd/jccolor-altivec.c
new file mode 100644
index 0000000..04b8708
--- /dev/null
+++ b/simd/jccolor-altivec.c
@@ -0,0 +1,104 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014, 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
+ * 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.
+ */
+
+/* RGB --> YCC CONVERSION */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_081 5329                 /* FIX(0.08131) */
+#define F_0_114 7471                 /* FIX(0.11400) */
+#define F_0_168 11059                /* FIX(0.16874) */
+#define F_0_250 16384                /* FIX(0.25000) */
+#define F_0_299 19595                /* FIX(0.29900) */
+#define F_0_331 21709                /* FIX(0.33126) */
+#define F_0_418 27439                /* FIX(0.41869) */
+#define F_0_500 32768                /* FIX(0.50000) */
+#define F_0_587 38470                /* FIX(0.58700) */
+#define F_0_337 (F_0_587 - F_0_250)  /* FIX(0.58700) - FIX(0.25000) */
+
+#define SCALEBITS 16
+#define ONE_HALF (1 << (SCALEBITS - 1))
+
+
+#define RGBG_INDEX0 {0,1,3,4,6,7,9,10,2,1,5,4,8,7,11,10}
+#define RGBG_INDEX1 {12,13,15,16,18,19,21,22,14,13,17,16,20,19,23,22}
+#define RGBG_INDEX2 {8,9,11,12,14,15,17,18,10,9,13,12,16,15,19,18}
+#define RGBG_INDEX3 {4,5,7,8,10,11,13,14,6,5,9,8,12,11,15,14}
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+
+#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
+#define jsimd_rgb_ycc_convert_altivec jsimd_extrgb_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX0
+#undef RGBG_INDEX1
+#undef RGBG_INDEX2
+#undef RGBG_INDEX3
+#undef jsimd_rgb_ycc_convert_altivec
+
+#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
+#define RGBG_INDEX {0,1,4,5,8,9,12,13,2,1,6,5,10,9,14,13}
+#define jsimd_rgb_ycc_convert_altivec jsimd_extrgbx_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_ycc_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
+#define RGBG_INDEX0 {2,1,5,4,8,7,11,10,0,1,3,4,6,7,9,10}
+#define RGBG_INDEX1 {14,13,17,16,20,19,23,22,12,13,15,16,18,19,21,22}
+#define RGBG_INDEX2 {10,9,13,12,16,15,19,18,8,9,11,12,14,15,17,18}
+#define RGBG_INDEX3 {6,5,9,8,12,11,15,14,4,5,7,8,10,11,13,14}
+#define jsimd_rgb_ycc_convert_altivec jsimd_extbgr_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX0
+#undef RGBG_INDEX1
+#undef RGBG_INDEX2
+#undef RGBG_INDEX3
+#undef jsimd_rgb_ycc_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
+#define RGBG_INDEX {2,1,6,5,10,9,14,13,0,1,4,5,8,9,12,13}
+#define jsimd_rgb_ycc_convert_altivec jsimd_extbgrx_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_ycc_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
+#define RGBG_INDEX {3,2,7,6,11,10,15,14,1,2,5,6,9,10,13,14}
+#define jsimd_rgb_ycc_convert_altivec jsimd_extxbgr_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_ycc_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
+#define RGBG_INDEX {1,2,5,6,9,10,13,14,3,2,7,6,11,10,15,14}
+#define jsimd_rgb_ycc_convert_altivec jsimd_extxrgb_ycc_convert_altivec
+#include "jccolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_ycc_convert_altivec
diff --git a/simd/jcgray-altivec.c b/simd/jcgray-altivec.c
new file mode 100644
index 0000000..b52fade
--- /dev/null
+++ b/simd/jcgray-altivec.c
@@ -0,0 +1,99 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014, 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
+ * 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.
+ */
+
+/* RGB --> GRAYSCALE CONVERSION */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_114 7471                 /* FIX(0.11400) */
+#define F_0_250 16384                /* FIX(0.25000) */
+#define F_0_299 19595                /* FIX(0.29900) */
+#define F_0_587 38470                /* FIX(0.58700) */
+#define F_0_337 (F_0_587 - F_0_250)  /* FIX(0.58700) - FIX(0.25000) */
+
+#define SCALEBITS 16
+#define ONE_HALF (1 << (SCALEBITS - 1))
+
+
+#define RGBG_INDEX0 {0,1,3,4,6,7,9,10,2,1,5,4,8,7,11,10}
+#define RGBG_INDEX1 {12,13,15,16,18,19,21,22,14,13,17,16,20,19,23,22}
+#define RGBG_INDEX2 {8,9,11,12,14,15,17,18,10,9,13,12,16,15,19,18}
+#define RGBG_INDEX3 {4,5,7,8,10,11,13,14,6,5,9,8,12,11,15,14}
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+
+#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
+#define jsimd_rgb_gray_convert_altivec jsimd_extrgb_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX0
+#undef RGBG_INDEX1
+#undef RGBG_INDEX2
+#undef RGBG_INDEX3
+#undef jsimd_rgb_gray_convert_altivec
+
+#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
+#define RGBG_INDEX {0,1,4,5,8,9,12,13,2,1,6,5,10,9,14,13}
+#define jsimd_rgb_gray_convert_altivec jsimd_extrgbx_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_gray_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
+#define RGBG_INDEX0 {2,1,5,4,8,7,11,10,0,1,3,4,6,7,9,10}
+#define RGBG_INDEX1 {14,13,17,16,20,19,23,22,12,13,15,16,18,19,21,22}
+#define RGBG_INDEX2 {10,9,13,12,16,15,19,18,8,9,11,12,14,15,17,18}
+#define RGBG_INDEX3 {6,5,9,8,12,11,15,14,4,5,7,8,10,11,13,14}
+#define jsimd_rgb_gray_convert_altivec jsimd_extbgr_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX0
+#undef RGBG_INDEX1
+#undef RGBG_INDEX2
+#undef RGBG_INDEX3
+#undef jsimd_rgb_gray_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
+#define RGBG_INDEX {2,1,6,5,10,9,14,13,0,1,4,5,8,9,12,13}
+#define jsimd_rgb_gray_convert_altivec jsimd_extbgrx_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_gray_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
+#define RGBG_INDEX {3,2,7,6,11,10,15,14,1,2,5,6,9,10,13,14}
+#define jsimd_rgb_gray_convert_altivec jsimd_extxbgr_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_gray_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
+#define RGBG_INDEX {1,2,5,6,9,10,13,14,3,2,7,6,11,10,15,14}
+#define jsimd_rgb_gray_convert_altivec jsimd_extxrgb_gray_convert_altivec
+#include "jcgryext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGBG_INDEX
+#undef jsimd_rgb_gray_convert_altivec
diff --git a/simd/jcgryext-altivec.c b/simd/jcgryext-altivec.c
new file mode 100644
index 0000000..c171615
--- /dev/null
+++ b/simd/jcgryext-altivec.c
@@ -0,0 +1,227 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, D. R. Commander.
+ * Copyright (C) 2014, Jay Foad.
+ * 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
+ * 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.
+ */
+
+/* This file is included by jcgray-altivec.c */
+
+
+void jsimd_rgb_gray_convert_altivec (JDIMENSION img_width,
+                                     JSAMPARRAY input_buf,
+                                     JSAMPIMAGE output_buf,
+                                     JDIMENSION output_row, int num_rows)
+{
+  JSAMPROW inptr, outptr;
+  int pitch = img_width * RGB_PIXELSIZE, num_cols;
+#if __BIG_ENDIAN__
+  int offset;
+  unsigned char __attribute__((aligned(16))) tmpbuf[RGB_PIXELSIZE * 16];
+#endif
+
+  __vector unsigned char rgb0, rgb1 = {0}, rgb2 = {0},
+    rgbg0, rgbg1, rgbg2, rgbg3, y;
+#if __BIG_ENDIAN__ || RGB_PIXELSIZE == 4
+  __vector unsigned char rgb3 = {0};
+#endif
+#if __BIG_ENDIAN__ && RGB_PIXELSIZE == 4
+  __vector unsigned char rgb4 = {0};
+#endif
+  __vector short rg0, rg1, rg2, rg3, bg0, bg1, bg2, bg3;
+  __vector unsigned short yl, yh;
+  __vector int y0, y1, y2, y3;
+
+  /* Constants */
+  __vector short pw_f0299_f0337 = { __4X2(F_0_299, F_0_337) },
+    pw_f0114_f0250 = { __4X2(F_0_114, F_0_250) };
+  __vector int pd_onehalf = { __4X(ONE_HALF) };
+  __vector unsigned char pb_zero = { __16X(0) },
+#if __BIG_ENDIAN__
+    shift_pack_index = {0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29};
+#else
+    shift_pack_index = {2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31};
+#endif
+
+  while (--num_rows >= 0) {
+    inptr = *input_buf++;
+    outptr = output_buf[0][output_row];
+    output_row++;
+
+    for (num_cols = pitch; num_cols > 0;
+         num_cols -= RGB_PIXELSIZE * 16, inptr += RGB_PIXELSIZE * 16,
+         outptr += 16) {
+
+#if __BIG_ENDIAN__
+      /* Load 16 pixels == 48 or 64 bytes */
+      offset = (size_t)inptr & 15;
+      if (offset) {
+        __vector unsigned char unaligned_shift_index;
+        int bytes = num_cols + offset;
+
+        if (bytes < (RGB_PIXELSIZE + 1) * 16 && (bytes & 15)) {
+          /* Slow path to prevent buffer overread.  Since there is no way to
+           * read a partial AltiVec register, overread would occur on the last
+           * chunk of the last image row if the right edge is not on a 16-byte
+           * boundary.  It could also occur on other rows if the bytes per row
+           * is low enough.  Since we can't determine whether we're on the last
+           * image row, we have to assume every row is the last.
+           */
+          memcpy(tmpbuf, inptr, min(num_cols, RGB_PIXELSIZE * 16));
+          rgb0 = vec_ld(0, tmpbuf);
+          rgb1 = vec_ld(16, tmpbuf);
+          rgb2 = vec_ld(32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          rgb3 = vec_ld(48, tmpbuf);
+#endif
+        } else {
+          /* Fast path */
+          rgb0 = vec_ld(0, inptr);
+          if (bytes > 16)
+            rgb1 = vec_ld(16, inptr);
+          if (bytes > 32)
+            rgb2 = vec_ld(32, inptr);
+          if (bytes > 48)
+            rgb3 = vec_ld(48, inptr);
+#if RGB_PIXELSIZE == 4
+          if (bytes > 64)
+            rgb4 = vec_ld(64, inptr);
+#endif
+          unaligned_shift_index = vec_lvsl(0, inptr);
+          rgb0 = vec_perm(rgb0, rgb1, unaligned_shift_index);
+          rgb1 = vec_perm(rgb1, rgb2, unaligned_shift_index);
+          rgb2 = vec_perm(rgb2, rgb3, unaligned_shift_index);
+#if RGB_PIXELSIZE == 4
+          rgb3 = vec_perm(rgb3, rgb4, unaligned_shift_index);
+#endif
+        }
+      } else {
+        if (num_cols < RGB_PIXELSIZE * 16 && (num_cols & 15)) {
+          /* Slow path */
+          memcpy(tmpbuf, inptr, min(num_cols, RGB_PIXELSIZE * 16));
+          rgb0 = vec_ld(0, tmpbuf);
+          rgb1 = vec_ld(16, tmpbuf);
+          rgb2 = vec_ld(32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          rgb3 = vec_ld(48, tmpbuf);
+#endif
+        } else {
+          /* Fast path */
+          rgb0 = vec_ld(0, inptr);
+          if (num_cols > 16)
+            rgb1 = vec_ld(16, inptr);
+          if (num_cols > 32)
+            rgb2 = vec_ld(32, inptr);
+#if RGB_PIXELSIZE == 4
+          if (num_cols > 48)
+            rgb3 = vec_ld(48, inptr);
+#endif
+        }
+      }
+#else
+      /* Little endian */
+      rgb0 = vec_vsx_ld(0, inptr);
+      if (num_cols > 16)
+        rgb1 = vec_vsx_ld(16, inptr);
+      if (num_cols > 32)
+        rgb2 = vec_vsx_ld(32, inptr);
+#if RGB_PIXELSIZE == 4
+      if (num_cols > 48)
+        rgb3 = vec_vsx_ld(48, inptr);
+#endif
+#endif
+
+#if RGB_PIXELSIZE == 3
+      /* rgb0 = R0 G0 B0 R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4 R5
+       * rgb1 = G5 B5 R6 G6 B6 R7 G7 B7 R8 G8 B8 R9 G9 B9 Ra Ga
+       * rgb2 = Ba Rb Gb Bb Rc Gc Bc Rd Gd Bd Re Ge Be Rf Gf Bf
+       *
+       * rgbg0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 G0 B1 G1 B2 G2 B3 G3
+       * rgbg1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 G4 B5 G5 B6 G6 B7 G7
+       * rgbg2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 G8 B9 G9 Ba Ga Bb Gb
+       * rgbg3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Gc Bd Gd Be Ge Bf Gf
+       */
+      rgbg0 = vec_perm(rgb0, rgb0, (__vector unsigned char)RGBG_INDEX0);
+      rgbg1 = vec_perm(rgb0, rgb1, (__vector unsigned char)RGBG_INDEX1);
+      rgbg2 = vec_perm(rgb1, rgb2, (__vector unsigned char)RGBG_INDEX2);
+      rgbg3 = vec_perm(rgb2, rgb2, (__vector unsigned char)RGBG_INDEX3);
+#else
+      /* rgb0 = R0 G0 B0 X0 R1 G1 B1 X1 R2 G2 B2 X2 R3 G3 B3 X3
+       * rgb1 = R4 G4 B4 X4 R5 G5 B5 X5 R6 G6 B6 X6 R7 G7 B7 X7
+       * rgb2 = R8 G8 B8 X8 R9 G9 B9 X9 Ra Ga Ba Xa Rb Gb Bb Xb
+       * rgb3 = Rc Gc Bc Xc Rd Gd Bd Xd Re Ge Be Xe Rf Gf Bf Xf
+       *
+       * rgbg0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 G0 B1 G1 B2 G2 B3 G3
+       * rgbg1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 G4 B5 G5 B6 G6 B7 G7
+       * rgbg2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 G8 B9 G9 Ba Ga Bb Gb
+       * rgbg3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Gc Bd Gd Be Ge Bf Gf
+       */
+      rgbg0 = vec_perm(rgb0, rgb0, (__vector unsigned char)RGBG_INDEX);
+      rgbg1 = vec_perm(rgb1, rgb1, (__vector unsigned char)RGBG_INDEX);
+      rgbg2 = vec_perm(rgb2, rgb2, (__vector unsigned char)RGBG_INDEX);
+      rgbg3 = vec_perm(rgb3, rgb3, (__vector unsigned char)RGBG_INDEX);
+#endif
+
+      /* rg0 = R0 G0 R1 G1 R2 G2 R3 G3
+       * bg0 = B0 G0 B1 G1 B2 G2 B3 G3
+       * ...
+       *
+       * NOTE: We have to use vec_merge*() here because vec_unpack*() doesn't
+       * support unsigned vectors.
+       */
+      rg0 = (__vector signed short)VEC_UNPACKHU(rgbg0);
+      bg0 = (__vector signed short)VEC_UNPACKLU(rgbg0);
+      rg1 = (__vector signed short)VEC_UNPACKHU(rgbg1);
+      bg1 = (__vector signed short)VEC_UNPACKLU(rgbg1);
+      rg2 = (__vector signed short)VEC_UNPACKHU(rgbg2);
+      bg2 = (__vector signed short)VEC_UNPACKLU(rgbg2);
+      rg3 = (__vector signed short)VEC_UNPACKHU(rgbg3);
+      bg3 = (__vector signed short)VEC_UNPACKLU(rgbg3);
+
+      /* (Original)
+       * Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
+       *
+       * (This implementation)
+       * Y  =  0.29900 * R + 0.33700 * G + 0.11400 * B + 0.25000 * G
+       */
+
+      /* Calculate Y values */
+
+      y0 = vec_msums(rg0, pw_f0299_f0337, pd_onehalf);
+      y1 = vec_msums(rg1, pw_f0299_f0337, pd_onehalf);
+      y2 = vec_msums(rg2, pw_f0299_f0337, pd_onehalf);
+      y3 = vec_msums(rg3, pw_f0299_f0337, pd_onehalf);
+      y0 = vec_msums(bg0, pw_f0114_f0250, y0);
+      y1 = vec_msums(bg1, pw_f0114_f0250, y1);
+      y2 = vec_msums(bg2, pw_f0114_f0250, y2);
+      y3 = vec_msums(bg3, pw_f0114_f0250, y3);
+      /* Clever way to avoid 4 shifts + 2 packs.  This packs the high word from
+       * each dword into a new 16-bit vector, which is the equivalent of
+       * descaling the 32-bit results (right-shifting by 16 bits) and then
+       * packing them.
+       */
+      yl = vec_perm((__vector unsigned short)y0, (__vector unsigned short)y1,
+                    shift_pack_index);
+      yh = vec_perm((__vector unsigned short)y2, (__vector unsigned short)y3,
+                    shift_pack_index);
+      y = vec_pack(yl, yh);
+      vec_st(y, 0, outptr);
+    }
+  }
+}
diff --git a/simd/jcsample-altivec.c b/simd/jcsample-altivec.c
new file mode 100644
index 0000000..603492d
--- /dev/null
+++ b/simd/jcsample-altivec.c
@@ -0,0 +1,158 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* CHROMA DOWNSAMPLING */
+
+#include "jsimd_altivec.h"
+#include "jcsample.h"
+
+
+void
+jsimd_h2v1_downsample_altivec (JDIMENSION image_width, int max_v_samp_factor,
+                               JDIMENSION v_samp_factor,
+                               JDIMENSION width_blocks,
+                               JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int outrow, outcol;
+  JDIMENSION output_cols = width_blocks * DCTSIZE;
+  JSAMPROW inptr, outptr;
+
+  __vector unsigned char this0, next0, out;
+  __vector unsigned short this0e, this0o, next0e, next0o, outl, outh;
+
+  /* Constants */
+  __vector unsigned short pw_bias = { __4X2(0, 1) },
+    pw_one = { __8X(1) };
+  __vector unsigned char even_odd_index =
+    {0,2,4,6,8,10,12,14,1,3,5,7,9,11,13,15},
+    pb_zero = { __16X(0) };
+
+  expand_right_edge(input_data, max_v_samp_factor, image_width,
+                    output_cols * 2);
+
+  for (outrow = 0; outrow < v_samp_factor; outrow++) {
+    outptr = output_data[outrow];
+    inptr = input_data[outrow];
+
+    for (outcol = output_cols; outcol > 0;
+         outcol -= 16, inptr += 32, outptr += 16) {
+
+      this0 = vec_ld(0, inptr);
+      this0 = vec_perm(this0, this0, even_odd_index);
+      this0e = (__vector unsigned short)VEC_UNPACKHU(this0);
+      this0o = (__vector unsigned short)VEC_UNPACKLU(this0);
+      outl = vec_add(this0e, this0o);
+      outl = vec_add(outl, pw_bias);
+      outl = vec_sr(outl, pw_one);
+
+      if (outcol > 8) {
+        next0 = vec_ld(16, inptr);
+        next0 = vec_perm(next0, next0, even_odd_index);
+        next0e = (__vector unsigned short)VEC_UNPACKHU(next0);
+        next0o = (__vector unsigned short)VEC_UNPACKLU(next0);
+        outh = vec_add(next0e, next0o);
+        outh = vec_add(outh, pw_bias);
+        outh = vec_sr(outh, pw_one);
+      } else
+        outh = vec_splat_u16(0);
+
+      out = vec_pack(outl, outh);
+      vec_st(out, 0, outptr);
+    }
+  }
+}
+
+
+void
+jsimd_h2v2_downsample_altivec (JDIMENSION image_width, int max_v_samp_factor,
+                               JDIMENSION v_samp_factor,
+                               JDIMENSION width_blocks,
+                               JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  int inrow, outrow, outcol;
+  JDIMENSION output_cols = width_blocks * DCTSIZE;
+  JSAMPROW inptr0, inptr1, outptr;
+
+  __vector unsigned char this0, next0, this1, next1, out;
+  __vector unsigned short this0e, this0o, next0e, next0o, this1e, this1o,
+    next1e, next1o, out0l, out0h, out1l, out1h, outl, outh;
+
+  /* Constants */
+  __vector unsigned short pw_bias = { __4X2(1, 2) },
+    pw_two = { __8X(2) };
+  __vector unsigned char even_odd_index =
+    { 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15 },
+    pb_zero = { __16X(0) };
+
+  expand_right_edge(input_data, max_v_samp_factor, image_width,
+                    output_cols * 2);
+
+  for (inrow = 0, outrow = 0; outrow < v_samp_factor;
+       inrow += 2, outrow++) {
+
+    inptr0 = input_data[inrow];
+    inptr1 = input_data[inrow + 1];
+    outptr = output_data[outrow];
+
+    for (outcol = output_cols; outcol > 0;
+         outcol -= 16, inptr0 += 32, inptr1 += 32, outptr += 16) {
+
+      this0 = vec_ld(0, inptr0);
+      this0 = vec_perm(this0, this0, even_odd_index);
+      this0e = (__vector unsigned short)VEC_UNPACKHU(this0);
+      this0o = (__vector unsigned short)VEC_UNPACKLU(this0);
+      out0l = vec_add(this0e, this0o);
+
+      this1 = vec_ld(0, inptr1);
+      this1 = vec_perm(this1, this1, even_odd_index);
+      this1e = (__vector unsigned short)VEC_UNPACKHU(this1);
+      this1o = (__vector unsigned short)VEC_UNPACKLU(this1);
+      out1l = vec_add(this1e, this1o);
+
+      outl = vec_add(out0l, out1l);
+      outl = vec_add(outl, pw_bias);
+      outl = vec_sr(outl, pw_two);
+
+      if (outcol > 8) {
+        next0 = vec_ld(16, inptr0);
+        next0 = vec_perm(next0, next0, even_odd_index);
+        next0e = (__vector unsigned short)VEC_UNPACKHU(next0);
+        next0o = (__vector unsigned short)VEC_UNPACKLU(next0);
+        out0h = vec_add(next0e, next0o);
+
+        next1 = vec_ld(16, inptr1);
+        next1 = vec_perm(next1, next1, even_odd_index);
+        next1e = (__vector unsigned short)VEC_UNPACKHU(next1);
+        next1o = (__vector unsigned short)VEC_UNPACKLU(next1);
+        out1h = vec_add(next1e, next1o);
+
+        outh = vec_add(out0h, out1h);
+        outh = vec_add(outh, pw_bias);
+        outh = vec_sr(outh, pw_two);
+      } else
+        outh = vec_splat_u16(0);
+
+      out = vec_pack(outl, outh);
+      vec_st(out, 0, outptr);
+    }
+  }
+}
diff --git a/simd/jcsample.h b/simd/jcsample.h
new file mode 100644
index 0000000..b1ef502
--- /dev/null
+++ b/simd/jcsample.h
@@ -0,0 +1,27 @@
+/*
+ * jcsample.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+LOCAL(void)
+expand_right_edge (JSAMPARRAY image_data, int num_rows,
+                   JDIMENSION input_cols, JDIMENSION output_cols)
+{
+  register JSAMPROW ptr;
+  register JSAMPLE pixval;
+  register int count;
+  int row;
+  int numcols = (int) (output_cols - input_cols);
+
+  if (numcols > 0) {
+    for (row = 0; row < num_rows; row++) {
+      ptr = image_data[row] + input_cols;
+      pixval = ptr[-1];         /* don't need GETJSAMPLE() here */
+      for (count = numcols; count > 0; count--)
+        *ptr++ = pixval;
+    }
+  }
+}
diff --git a/simd/jdcolext-altivec.c b/simd/jdcolext-altivec.c
new file mode 100644
index 0000000..1ae91b9
--- /dev/null
+++ b/simd/jdcolext-altivec.c
@@ -0,0 +1,274 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* This file is included by jdcolor-altivec.c */
+
+
+void jsimd_ycc_rgb_convert_altivec (JDIMENSION out_width, JSAMPIMAGE input_buf,
+                                    JDIMENSION input_row,
+                                    JSAMPARRAY output_buf, int num_rows)
+{
+  JSAMPROW outptr, inptr0, inptr1, inptr2;
+  int pitch = out_width * RGB_PIXELSIZE, num_cols;
+#if __BIG_ENDIAN__
+  int offset;
+#endif
+  unsigned char __attribute__((aligned(16))) tmpbuf[RGB_PIXELSIZE * 16];
+
+  __vector unsigned char rgb0, rgb1, rgb2, rgbx0, rgbx1, rgbx2, rgbx3,
+    y, cb, cr;
+#if __BIG_ENDIAN__
+  __vector unsigned char edgel, edgeh, edges, out0, out1, out2, out3;
+#if RGB_PIXELSIZE == 4
+  __vector unsigned char out4;
+#endif
+#endif
+#if RGB_PIXELSIZE == 4
+  __vector unsigned char rgb3;
+#endif
+  __vector short rg0, rg1, rg2, rg3, bx0, bx1, bx2, bx3, yl, yh, cbl, cbh,
+    crl, crh, rl, rh, gl, gh, bl, bh, g0w, g1w, g2w, g3w;
+  __vector int g0, g1, g2, g3;
+
+  /* Constants
+   * NOTE: The >> 1 is to compensate for the fact that vec_madds() returns 17
+   * high-order bits, not 16.
+   */
+  __vector short pw_f0402 = { __8X(F_0_402 >> 1) },
+    pw_mf0228 = { __8X(-F_0_228 >> 1) },
+    pw_mf0344_f0285 = { __4X2(-F_0_344, F_0_285) },
+    pw_one = { __8X(1) }, pw_255 = { __8X(255) },
+    pw_cj = { __8X(CENTERJSAMPLE) };
+  __vector int pd_onehalf = { __4X(ONE_HALF) };
+  __vector unsigned char pb_zero = { __16X(0) },
+#if __BIG_ENDIAN__
+    shift_pack_index = {0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29};
+#else
+    shift_pack_index = {2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31};
+#endif
+
+  while (--num_rows >= 0) {
+    inptr0 = input_buf[0][input_row];
+    inptr1 = input_buf[1][input_row];
+    inptr2 = input_buf[2][input_row];
+    input_row++;
+    outptr = *output_buf++;
+
+    for (num_cols = pitch; num_cols > 0;
+         num_cols -= RGB_PIXELSIZE * 16, outptr += RGB_PIXELSIZE * 16,
+         inptr0 += 16, inptr1 += 16, inptr2 += 16) {
+
+      y = vec_ld(0, inptr0);
+      /* NOTE: We have to use vec_merge*() here because vec_unpack*() doesn't
+       * support unsigned vectors.
+       */
+      yl = (__vector signed short)VEC_UNPACKHU(y);
+      yh = (__vector signed short)VEC_UNPACKLU(y);
+
+      cb = vec_ld(0, inptr1);
+      cbl = (__vector signed short)VEC_UNPACKHU(cb);
+      cbh = (__vector signed short)VEC_UNPACKLU(cb);
+      cbl = vec_sub(cbl, pw_cj);
+      cbh = vec_sub(cbh, pw_cj);
+
+      cr = vec_ld(0, inptr2);
+      crl = (__vector signed short)VEC_UNPACKHU(cr);
+      crh = (__vector signed short)VEC_UNPACKLU(cr);
+      crl = vec_sub(crl, pw_cj);
+      crh = vec_sub(crh, pw_cj);
+
+      /* (Original)
+       * R = Y                + 1.40200 * Cr
+       * G = Y - 0.34414 * Cb - 0.71414 * Cr
+       * B = Y + 1.77200 * Cb
+       *
+       * (This implementation)
+       * R = Y                + 0.40200 * Cr + Cr
+       * G = Y - 0.34414 * Cb + 0.28586 * Cr - Cr
+       * B = Y - 0.22800 * Cb + Cb + Cb
+       */
+      bl = vec_add(cbl, cbl);
+      bh = vec_add(cbh, cbh);
+      bl = vec_madds(bl, pw_mf0228, pw_one);
+      bh = vec_madds(bh, pw_mf0228, pw_one);
+      bl = vec_sra(bl, (__vector unsigned short)pw_one);
+      bh = vec_sra(bh, (__vector unsigned short)pw_one);
+      bl = vec_add(bl, cbl);
+      bh = vec_add(bh, cbh);
+      bl = vec_add(bl, cbl);
+      bh = vec_add(bh, cbh);
+      bl = vec_add(bl, yl);
+      bh = vec_add(bh, yh);
+
+      rl = vec_add(crl, crl);
+      rh = vec_add(crh, crh);
+      rl = vec_madds(rl, pw_f0402, pw_one);
+      rh = vec_madds(rh, pw_f0402, pw_one);
+      rl = vec_sra(rl, (__vector unsigned short)pw_one);
+      rh = vec_sra(rh, (__vector unsigned short)pw_one);
+      rl = vec_add(rl, crl);
+      rh = vec_add(rh, crh);
+      rl = vec_add(rl, yl);
+      rh = vec_add(rh, yh);
+
+      g0w = vec_mergeh(cbl, crl);
+      g1w = vec_mergel(cbl, crl);
+      g0 = vec_msums(g0w, pw_mf0344_f0285, pd_onehalf);
+      g1 = vec_msums(g1w, pw_mf0344_f0285, pd_onehalf);
+      g2w = vec_mergeh(cbh, crh);
+      g3w = vec_mergel(cbh, crh);
+      g2 = vec_msums(g2w, pw_mf0344_f0285, pd_onehalf);
+      g3 = vec_msums(g3w, pw_mf0344_f0285, pd_onehalf);
+      /* Clever way to avoid 4 shifts + 2 packs.  This packs the high word from
+       * each dword into a new 16-bit vector, which is the equivalent of
+       * descaling the 32-bit results (right-shifting by 16 bits) and then
+       * packing them.
+       */
+      gl = vec_perm((__vector short)g0, (__vector short)g1, shift_pack_index);
+      gh = vec_perm((__vector short)g2, (__vector short)g3, shift_pack_index);
+      gl = vec_sub(gl, crl);
+      gh = vec_sub(gh, crh);
+      gl = vec_add(gl, yl);
+      gh = vec_add(gh, yh);
+
+      rg0 = vec_mergeh(rl, gl);
+      bx0 = vec_mergeh(bl, pw_255);
+      rg1 = vec_mergel(rl, gl);
+      bx1 = vec_mergel(bl, pw_255);
+      rg2 = vec_mergeh(rh, gh);
+      bx2 = vec_mergeh(bh, pw_255);
+      rg3 = vec_mergel(rh, gh);
+      bx3 = vec_mergel(bh, pw_255);
+
+      rgbx0 = vec_packsu(rg0, bx0);
+      rgbx1 = vec_packsu(rg1, bx1);
+      rgbx2 = vec_packsu(rg2, bx2);
+      rgbx3 = vec_packsu(rg3, bx3);
+
+#if RGB_PIXELSIZE == 3
+      /* rgbx0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 X0 B1 X1 B2 X2 B3 X3
+       * rgbx1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 X4 B5 X5 B6 X6 B7 X7
+       * rgbx2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 X8 B9 X9 Ba Xa Bb Xb
+       * rgbx3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Xc Bd Xd Be Xe Bf Xf
+       *
+       * rgb0 = R0 G0 B0 R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4 R5
+       * rgb1 = G5 B5 R6 G6 B6 R7 G7 B7 R8 G8 B8 R9 G9 B9 Ra Ga
+       * rgb2 = Ba Rb Gb Bb Rc Gc Bc Rd Gd Bd Re Ge Be Rf Gf Bf
+       */
+      rgb0 = vec_perm(rgbx0, rgbx1, (__vector unsigned char)RGB_INDEX0);
+      rgb1 = vec_perm(rgbx1, rgbx2, (__vector unsigned char)RGB_INDEX1);
+      rgb2 = vec_perm(rgbx2, rgbx3, (__vector unsigned char)RGB_INDEX2);
+#else
+      /* rgbx0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 X0 B1 X1 B2 X2 B3 X3
+       * rgbx1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 X4 B5 X5 B6 X6 B7 X7
+       * rgbx2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 X8 B9 X9 Ba Xa Bb Xb
+       * rgbx3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Xc Bd Xd Be Xe Bf Xf
+       *
+       * rgb0 = R0 G0 B0 X0 R1 G1 B1 X1 R2 G2 B2 X2 R3 G3 B3 X3
+       * rgb1 = R4 G4 B4 X4 R5 G5 B5 X5 R6 G6 B6 X6 R7 G7 B7 X7
+       * rgb2 = R8 G8 B8 X8 R9 G9 B9 X9 Ra Ga Ba Xa Rb Gb Bb Xb
+       * rgb3 = Rc Gc Bc Xc Rd Gd Bd Xd Re Ge Be Xe Rf Gf Bf Xf
+       */
+      rgb0 = vec_perm(rgbx0, rgbx0, (__vector unsigned char)RGB_INDEX);
+      rgb1 = vec_perm(rgbx1, rgbx1, (__vector unsigned char)RGB_INDEX);
+      rgb2 = vec_perm(rgbx2, rgbx2, (__vector unsigned char)RGB_INDEX);
+      rgb3 = vec_perm(rgbx3, rgbx3, (__vector unsigned char)RGB_INDEX);
+#endif
+
+#if __BIG_ENDIAN__
+      offset = (size_t)outptr & 15;
+      if (offset) {
+        __vector unsigned char unaligned_shift_index;
+        int bytes = num_cols + offset;
+
+        if (bytes < (RGB_PIXELSIZE + 1) * 16 && (bytes & 15)) {
+          /* Slow path to prevent buffer overwrite.  Since there is no way to
+           * write a partial AltiVec register, overwrite would occur on the
+           * last chunk of the last image row if the right edge is not on a
+           * 16-byte boundary.  It could also occur on other rows if the bytes
+           * per row is low enough.  Since we can't determine whether we're on
+           * the last image row, we have to assume every row is the last.
+           */
+          vec_st(rgb0, 0, tmpbuf);
+          vec_st(rgb1, 16, tmpbuf);
+          vec_st(rgb2, 32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          vec_st(rgb3, 48, tmpbuf);
+#endif
+          memcpy(outptr, tmpbuf, min(num_cols, RGB_PIXELSIZE * 16));
+        } else {
+          /* Fast path */
+          unaligned_shift_index = vec_lvsl(0, outptr);
+          edgel = vec_ld(0, outptr);
+          edgeh = vec_ld(min(num_cols - 1, RGB_PIXELSIZE * 16), outptr);
+          edges = vec_perm(edgeh, edgel, unaligned_shift_index);
+          unaligned_shift_index = vec_lvsr(0, outptr);
+          out0 = vec_perm(edges, rgb0, unaligned_shift_index);
+          out1 = vec_perm(rgb0, rgb1, unaligned_shift_index);
+          out2 = vec_perm(rgb1, rgb2, unaligned_shift_index);
+#if RGB_PIXELSIZE == 4
+          out3 = vec_perm(rgb2, rgb3, unaligned_shift_index);
+          out4 = vec_perm(rgb3, edges, unaligned_shift_index);
+#else
+          out3 = vec_perm(rgb2, edges, unaligned_shift_index);
+#endif
+          vec_st(out0, 0, outptr);
+          if (bytes > 16)
+            vec_st(out1, 16, outptr);
+          if (bytes > 32)
+            vec_st(out2, 32, outptr);
+          if (bytes > 48)
+            vec_st(out3, 48, outptr);
+#if RGB_PIXELSIZE == 4
+          if (bytes > 64)
+            vec_st(out4, 64, outptr);
+#endif
+        }
+      } else {
+#endif /* __BIG_ENDIAN__ */
+        if (num_cols < RGB_PIXELSIZE * 16 && (num_cols & 15)) {
+          /* Slow path */
+          VEC_ST(rgb0, 0, tmpbuf);
+          VEC_ST(rgb1, 16, tmpbuf);
+          VEC_ST(rgb2, 32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          VEC_ST(rgb3, 48, tmpbuf);
+#endif
+          memcpy(outptr, tmpbuf, min(num_cols, RGB_PIXELSIZE * 16));
+        } else {
+          /* Fast path */
+          VEC_ST(rgb0, 0, outptr);
+          if (num_cols > 16)
+            VEC_ST(rgb1, 16, outptr);
+          if (num_cols > 32)
+            VEC_ST(rgb2, 32, outptr);
+#if RGB_PIXELSIZE == 4
+          if (num_cols > 48)
+            VEC_ST(rgb3, 48, outptr);
+#endif
+        }
+#if __BIG_ENDIAN__
+      }
+#endif
+    }
+  }
+}
diff --git a/simd/jdcolor-altivec.c b/simd/jdcolor-altivec.c
new file mode 100644
index 0000000..e0892d8
--- /dev/null
+++ b/simd/jdcolor-altivec.c
@@ -0,0 +1,96 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* YCC --> RGB CONVERSION */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_344 22554              /* FIX(0.34414) */
+#define F_0_714 46802              /* FIX(0.71414) */
+#define F_1_402 91881              /* FIX(1.40200) */
+#define F_1_772 116130             /* FIX(1.77200) */
+#define F_0_402 (F_1_402 - 65536)  /* FIX(1.40200) - FIX(1) */
+#define F_0_285 (65536 - F_0_714)  /* FIX(1) - FIX(0.71414) */
+#define F_0_228 (131072 - F_1_772) /* FIX(2) - FIX(1.77200) */
+
+#define SCALEBITS 16
+#define ONE_HALF (1 << (SCALEBITS - 1))
+
+#define RGB_INDEX0 {0,1,8,2,3,10,4,5,12,6,7,14,16,17,24,18}
+#define RGB_INDEX1 {3,10,4,5,12,6,7,14,16,17,24,18,19,26,20,21}
+#define RGB_INDEX2 {12,6,7,14,16,17,24,18,19,26,20,21,28,22,23,30}
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+
+#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extrgb_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX0
+#undef RGB_INDEX1
+#undef RGB_INDEX2
+#undef jsimd_ycc_rgb_convert_altivec
+
+#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
+#define RGB_INDEX {0,1,8,9,2,3,10,11,4,5,12,13,6,7,14,15}
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extrgbx_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_ycc_rgb_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
+#define RGB_INDEX0 {8,1,0,10,3,2,12,5,4,14,7,6,24,17,16,26}
+#define RGB_INDEX1 {3,2,12,5,4,14,7,6,24,17,16,26,19,18,28,21}
+#define RGB_INDEX2 {4,14,7,6,24,17,16,26,19,18,28,21,20,30,23,22}
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extbgr_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX0
+#undef RGB_INDEX1
+#undef RGB_INDEX2
+#undef jsimd_ycc_rgb_convert_altivec
+
+#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
+#define RGB_INDEX {8,1,0,9,10,3,2,11,12,5,4,13,14,7,6,15}
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extbgrx_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_ycc_rgb_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
+#define RGB_INDEX {9,8,1,0,11,10,3,2,13,12,5,4,15,14,7,6}
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extxbgr_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_ycc_rgb_convert_altivec
+
+#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
+#define RGB_INDEX {9,0,1,8,11,2,3,10,13,4,5,12,15,6,7,14}
+#define jsimd_ycc_rgb_convert_altivec jsimd_ycc_extxrgb_convert_altivec
+#include "jdcolext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_ycc_rgb_convert_altivec
diff --git a/simd/jdmerge-altivec.c b/simd/jdmerge-altivec.c
new file mode 100644
index 0000000..cc8d3d9
--- /dev/null
+++ b/simd/jdmerge-altivec.c
@@ -0,0 +1,108 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* MERGED YCC --> RGB CONVERSION AND UPSAMPLING */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_344 22554              /* FIX(0.34414) */
+#define F_0_714 46802              /* FIX(0.71414) */
+#define F_1_402 91881              /* FIX(1.40200) */
+#define F_1_772 116130             /* FIX(1.77200) */
+#define F_0_402 (F_1_402 - 65536)  /* FIX(1.40200) - FIX(1) */
+#define F_0_285 (65536 - F_0_714)  /* FIX(1) - FIX(0.71414) */
+#define F_0_228 (131072 - F_1_772) /* FIX(2) - FIX(1.77200) */
+
+#define SCALEBITS 16
+#define ONE_HALF (1 << (SCALEBITS - 1))
+
+#define RGB_INDEX0 {0,1,8,2,3,10,4,5,12,6,7,14,16,17,24,18}
+#define RGB_INDEX1 {3,10,4,5,12,6,7,14,16,17,24,18,19,26,20,21}
+#define RGB_INDEX2 {12,6,7,14,16,17,24,18,19,26,20,21,28,22,23,30}
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+
+#define RGB_PIXELSIZE EXT_RGB_PIXELSIZE
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extrgb_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extrgb_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX0
+#undef RGB_INDEX1
+#undef RGB_INDEX2
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
+
+#define RGB_PIXELSIZE EXT_RGBX_PIXELSIZE
+#define RGB_INDEX {0,1,8,9,2,3,10,11,4,5,12,13,6,7,14,15}
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extrgbx_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extrgbx_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
+
+#define RGB_PIXELSIZE EXT_BGR_PIXELSIZE
+#define RGB_INDEX0 {8,1,0,10,3,2,12,5,4,14,7,6,24,17,16,26}
+#define RGB_INDEX1 {3,2,12,5,4,14,7,6,24,17,16,26,19,18,28,21}
+#define RGB_INDEX2 {4,14,7,6,24,17,16,26,19,18,28,21,20,30,23,22}
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extbgr_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extbgr_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX0
+#undef RGB_INDEX1
+#undef RGB_INDEX2
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
+
+#define RGB_PIXELSIZE EXT_BGRX_PIXELSIZE
+#define RGB_INDEX {8,1,0,9,10,3,2,11,12,5,4,13,14,7,6,15}
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extbgrx_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extbgrx_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
+
+#define RGB_PIXELSIZE EXT_XBGR_PIXELSIZE
+#define RGB_INDEX {9,8,1,0,11,10,3,2,13,12,5,4,15,14,7,6}
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extxbgr_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extxbgr_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
+
+#define RGB_PIXELSIZE EXT_XRGB_PIXELSIZE
+#define RGB_INDEX {9,0,1,8,11,2,3,10,13,4,5,12,15,6,7,14}
+#define jsimd_h2v1_merged_upsample_altivec jsimd_h2v1_extxrgb_merged_upsample_altivec
+#define jsimd_h2v2_merged_upsample_altivec jsimd_h2v2_extxrgb_merged_upsample_altivec
+#include "jdmrgext-altivec.c"
+#undef RGB_PIXELSIZE
+#undef RGB_INDEX
+#undef jsimd_h2v1_merged_upsample_altivec
+#undef jsimd_h2v2_merged_upsample_altivec
diff --git a/simd/jdmrgext-altivec.c b/simd/jdmrgext-altivec.c
new file mode 100644
index 0000000..3b6950d
--- /dev/null
+++ b/simd/jdmrgext-altivec.c
@@ -0,0 +1,323 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* This file is included by jdmerge-altivec.c */
+
+
+void jsimd_h2v1_merged_upsample_altivec (JDIMENSION output_width,
+                                         JSAMPIMAGE input_buf,
+                                         JDIMENSION in_row_group_ctr,
+                                         JSAMPARRAY output_buf)
+{
+  JSAMPROW outptr, inptr0, inptr1, inptr2;
+  int pitch = output_width * RGB_PIXELSIZE, num_cols, yloop;
+#if __BIG_ENDIAN__
+  int offset;
+#endif
+  unsigned char __attribute__((aligned(16))) tmpbuf[RGB_PIXELSIZE * 16];
+
+  __vector unsigned char rgb0, rgb1, rgb2, rgbx0, rgbx1, rgbx2, rgbx3,
+    y, cb, cr;
+#if __BIG_ENDIAN__
+  __vector unsigned char edgel, edgeh, edges, out0, out1, out2, out3;
+#if RGB_PIXELSIZE == 4
+  __vector unsigned char out4;
+#endif
+#endif
+#if RGB_PIXELSIZE == 4
+  __vector unsigned char rgb3;
+#endif
+  __vector short rg0, rg1, rg2, rg3, bx0, bx1, bx2, bx3, ye, yo, cbl, cbh,
+    crl, crh, r_yl, r_yh, g_yl, g_yh, b_yl, b_yh, g_y0w, g_y1w, g_y2w, g_y3w,
+    rl, rh, gl, gh, bl, bh, re, ro, ge, go, be, bo;
+  __vector int g_y0, g_y1, g_y2, g_y3;
+
+  /* Constants
+   * NOTE: The >> 1 is to compensate for the fact that vec_madds() returns 17
+   * high-order bits, not 16.
+   */
+  __vector short pw_f0402 = { __8X(F_0_402 >> 1) },
+    pw_mf0228 = { __8X(-F_0_228 >> 1) },
+    pw_mf0344_f0285 = { __4X2(-F_0_344, F_0_285) },
+    pw_one = { __8X(1) }, pw_255 = { __8X(255) },
+    pw_cj = { __8X(CENTERJSAMPLE) };
+  __vector int pd_onehalf = { __4X(ONE_HALF) };
+  __vector unsigned char pb_zero = { __16X(0) },
+#if __BIG_ENDIAN__
+    shift_pack_index = {0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29},
+    even_index = {0,16,0,18,0,20,0,22,0,24,0,26,0,28,0,30},
+    odd_index = {0,17,0,19,0,21,0,23,0,25,0,27,0,29,0,31};
+#else
+    shift_pack_index = {2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31},
+    even_index = {16,0,18,0,20,0,22,0,24,0,26,0,28,0,30,0},
+    odd_index = {17,0,19,0,21,0,23,0,25,0,27,0,29,0,31,0};
+#endif
+
+  inptr0 = input_buf[0][in_row_group_ctr];
+  inptr1 = input_buf[1][in_row_group_ctr];
+  inptr2 = input_buf[2][in_row_group_ctr];
+  outptr = output_buf[0];
+
+  for (num_cols = pitch; num_cols > 0; inptr1 += 16, inptr2 += 16) {
+
+    cb = vec_ld(0, inptr1);
+    /* NOTE: We have to use vec_merge*() here because vec_unpack*() doesn't
+     * support unsigned vectors.
+     */
+    cbl = (__vector signed short)VEC_UNPACKHU(cb);
+    cbh = (__vector signed short)VEC_UNPACKLU(cb);
+    cbl = vec_sub(cbl, pw_cj);
+    cbh = vec_sub(cbh, pw_cj);
+
+    cr = vec_ld(0, inptr2);
+    crl = (__vector signed short)VEC_UNPACKHU(cr);
+    crh = (__vector signed short)VEC_UNPACKLU(cr);
+    crl = vec_sub(crl, pw_cj);
+    crh = vec_sub(crh, pw_cj);
+
+    /* (Original)
+     * R = Y                + 1.40200 * Cr
+     * G = Y - 0.34414 * Cb - 0.71414 * Cr
+     * B = Y + 1.77200 * Cb
+     *
+     * (This implementation)
+     * R = Y                + 0.40200 * Cr + Cr
+     * G = Y - 0.34414 * Cb + 0.28586 * Cr - Cr
+     * B = Y - 0.22800 * Cb + Cb + Cb
+     */
+    b_yl = vec_add(cbl, cbl);
+    b_yh = vec_add(cbh, cbh);
+    b_yl = vec_madds(b_yl, pw_mf0228, pw_one);
+    b_yh = vec_madds(b_yh, pw_mf0228, pw_one);
+    b_yl = vec_sra(b_yl, (__vector unsigned short)pw_one);
+    b_yh = vec_sra(b_yh, (__vector unsigned short)pw_one);
+    b_yl = vec_add(b_yl, cbl);
+    b_yh = vec_add(b_yh, cbh);
+    b_yl = vec_add(b_yl, cbl);
+    b_yh = vec_add(b_yh, cbh);
+
+    r_yl = vec_add(crl, crl);
+    r_yh = vec_add(crh, crh);
+    r_yl = vec_madds(r_yl, pw_f0402, pw_one);
+    r_yh = vec_madds(r_yh, pw_f0402, pw_one);
+    r_yl = vec_sra(r_yl, (__vector unsigned short)pw_one);
+    r_yh = vec_sra(r_yh, (__vector unsigned short)pw_one);
+    r_yl = vec_add(r_yl, crl);
+    r_yh = vec_add(r_yh, crh);
+
+    g_y0w = vec_mergeh(cbl, crl);
+    g_y1w = vec_mergel(cbl, crl);
+    g_y0 = vec_msums(g_y0w, pw_mf0344_f0285, pd_onehalf);
+    g_y1 = vec_msums(g_y1w, pw_mf0344_f0285, pd_onehalf);
+    g_y2w = vec_mergeh(cbh, crh);
+    g_y3w = vec_mergel(cbh, crh);
+    g_y2 = vec_msums(g_y2w, pw_mf0344_f0285, pd_onehalf);
+    g_y3 = vec_msums(g_y3w, pw_mf0344_f0285, pd_onehalf);
+    /* Clever way to avoid 4 shifts + 2 packs.  This packs the high word from
+     * each dword into a new 16-bit vector, which is the equivalent of
+     * descaling the 32-bit results (right-shifting by 16 bits) and then
+     * packing them.
+     */
+    g_yl = vec_perm((__vector short)g_y0, (__vector short)g_y1,
+                    shift_pack_index);
+    g_yh = vec_perm((__vector short)g_y2, (__vector short)g_y3,
+                    shift_pack_index);
+    g_yl = vec_sub(g_yl, crl);
+    g_yh = vec_sub(g_yh, crh);
+
+    for (yloop = 0; yloop < 2 && num_cols > 0; yloop++,
+         num_cols -= RGB_PIXELSIZE * 16,
+         outptr += RGB_PIXELSIZE * 16, inptr0 += 16) {
+
+      y = vec_ld(0, inptr0);
+      ye = (__vector signed short)vec_perm(pb_zero, y, even_index);
+      yo = (__vector signed short)vec_perm(pb_zero, y, odd_index);
+
+      if (yloop == 0) {
+        be = vec_add(b_yl, ye);
+        bo = vec_add(b_yl, yo);
+        re = vec_add(r_yl, ye);
+        ro = vec_add(r_yl, yo);
+        ge = vec_add(g_yl, ye);
+        go = vec_add(g_yl, yo);
+      } else {
+        be = vec_add(b_yh, ye);
+        bo = vec_add(b_yh, yo);
+        re = vec_add(r_yh, ye);
+        ro = vec_add(r_yh, yo);
+        ge = vec_add(g_yh, ye);
+        go = vec_add(g_yh, yo);
+      }
+
+      rl = vec_mergeh(re, ro);
+      rh = vec_mergel(re, ro);
+      gl = vec_mergeh(ge, go);
+      gh = vec_mergel(ge, go);
+      bl = vec_mergeh(be, bo);
+      bh = vec_mergel(be, bo);
+
+      rg0 = vec_mergeh(rl, gl);
+      bx0 = vec_mergeh(bl, pw_255);
+      rg1 = vec_mergel(rl, gl);
+      bx1 = vec_mergel(bl, pw_255);
+      rg2 = vec_mergeh(rh, gh);
+      bx2 = vec_mergeh(bh, pw_255);
+      rg3 = vec_mergel(rh, gh);
+      bx3 = vec_mergel(bh, pw_255);
+
+      rgbx0 = vec_packsu(rg0, bx0);
+      rgbx1 = vec_packsu(rg1, bx1);
+      rgbx2 = vec_packsu(rg2, bx2);
+      rgbx3 = vec_packsu(rg3, bx3);
+
+#if RGB_PIXELSIZE == 3
+      /* rgbx0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 X0 B1 X1 B2 X2 B3 X3
+       * rgbx1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 X4 B5 X5 B6 X6 B7 X7
+       * rgbx2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 X8 B9 X9 Ba Xa Bb Xb
+       * rgbx3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Xc Bd Xd Be Xe Bf Xf
+       *
+       * rgb0 = R0 G0 B0 R1 G1 B1 R2 G2 B2 R3 G3 B3 R4 G4 B4 R5
+       * rgb1 = G5 B5 R6 G6 B6 R7 G7 B7 R8 G8 B8 R9 G9 B9 Ra Ga
+       * rgb2 = Ba Rb Gb Bb Rc Gc Bc Rd Gd Bd Re Ge Be Rf Gf Bf
+       */
+      rgb0 = vec_perm(rgbx0, rgbx1, (__vector unsigned char)RGB_INDEX0);
+      rgb1 = vec_perm(rgbx1, rgbx2, (__vector unsigned char)RGB_INDEX1);
+      rgb2 = vec_perm(rgbx2, rgbx3, (__vector unsigned char)RGB_INDEX2);
+#else
+      /* rgbx0 = R0 G0 R1 G1 R2 G2 R3 G3 B0 X0 B1 X1 B2 X2 B3 X3
+       * rgbx1 = R4 G4 R5 G5 R6 G6 R7 G7 B4 X4 B5 X5 B6 X6 B7 X7
+       * rgbx2 = R8 G8 R9 G9 Ra Ga Rb Gb B8 X8 B9 X9 Ba Xa Bb Xb
+       * rgbx3 = Rc Gc Rd Gd Re Ge Rf Gf Bc Xc Bd Xd Be Xe Bf Xf
+       *
+       * rgb0 = R0 G0 B0 X0 R1 G1 B1 X1 R2 G2 B2 X2 R3 G3 B3 X3
+       * rgb1 = R4 G4 B4 X4 R5 G5 B5 X5 R6 G6 B6 X6 R7 G7 B7 X7
+       * rgb2 = R8 G8 B8 X8 R9 G9 B9 X9 Ra Ga Ba Xa Rb Gb Bb Xb
+       * rgb3 = Rc Gc Bc Xc Rd Gd Bd Xd Re Ge Be Xe Rf Gf Bf Xf
+       */
+      rgb0 = vec_perm(rgbx0, rgbx0, (__vector unsigned char)RGB_INDEX);
+      rgb1 = vec_perm(rgbx1, rgbx1, (__vector unsigned char)RGB_INDEX);
+      rgb2 = vec_perm(rgbx2, rgbx2, (__vector unsigned char)RGB_INDEX);
+      rgb3 = vec_perm(rgbx3, rgbx3, (__vector unsigned char)RGB_INDEX);
+#endif
+
+#if __BIG_ENDIAN__
+      offset = (size_t)outptr & 15;
+      if (offset) {
+        __vector unsigned char unaligned_shift_index;
+        int bytes = num_cols + offset;
+
+        if (bytes < (RGB_PIXELSIZE + 1) * 16 && (bytes & 15)) {
+          /* Slow path to prevent buffer overwrite.  Since there is no way to
+           * write a partial AltiVec register, overwrite would occur on the
+           * last chunk of the last image row if the right edge is not on a
+           * 16-byte boundary.  It could also occur on other rows if the bytes
+           * per row is low enough.  Since we can't determine whether we're on
+           * the last image row, we have to assume every row is the last.
+           */
+          vec_st(rgb0, 0, tmpbuf);
+          vec_st(rgb1, 16, tmpbuf);
+          vec_st(rgb2, 32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          vec_st(rgb3, 48, tmpbuf);
+#endif
+          memcpy(outptr, tmpbuf, min(num_cols, RGB_PIXELSIZE * 16));
+        } else {
+          /* Fast path */
+          unaligned_shift_index = vec_lvsl(0, outptr);
+          edgel = vec_ld(0, outptr);
+          edgeh = vec_ld(min(num_cols - 1, RGB_PIXELSIZE * 16), outptr);
+          edges = vec_perm(edgeh, edgel, unaligned_shift_index);
+          unaligned_shift_index = vec_lvsr(0, outptr);
+          out0 = vec_perm(edges, rgb0, unaligned_shift_index);
+          out1 = vec_perm(rgb0, rgb1, unaligned_shift_index);
+          out2 = vec_perm(rgb1, rgb2, unaligned_shift_index);
+#if RGB_PIXELSIZE == 4
+          out3 = vec_perm(rgb2, rgb3, unaligned_shift_index);
+          out4 = vec_perm(rgb3, edges, unaligned_shift_index);
+#else
+          out3 = vec_perm(rgb2, edges, unaligned_shift_index);
+#endif
+          vec_st(out0, 0, outptr);
+          if (bytes > 16)
+            vec_st(out1, 16, outptr);
+          if (bytes > 32)
+            vec_st(out2, 32, outptr);
+          if (bytes > 48)
+            vec_st(out3, 48, outptr);
+#if RGB_PIXELSIZE == 4
+          if (bytes > 64)
+            vec_st(out4, 64, outptr);
+#endif
+        }
+      } else {
+#endif /* __BIG_ENDIAN__ */
+        if (num_cols < RGB_PIXELSIZE * 16 && (num_cols & 15)) {
+          /* Slow path */
+          VEC_ST(rgb0, 0, tmpbuf);
+          VEC_ST(rgb1, 16, tmpbuf);
+          VEC_ST(rgb2, 32, tmpbuf);
+#if RGB_PIXELSIZE == 4
+          VEC_ST(rgb3, 48, tmpbuf);
+#endif
+          memcpy(outptr, tmpbuf, min(num_cols, RGB_PIXELSIZE * 16));
+        } else {
+          /* Fast path */
+          VEC_ST(rgb0, 0, outptr);
+          if (num_cols > 16)
+            VEC_ST(rgb1, 16, outptr);
+          if (num_cols > 32)
+            VEC_ST(rgb2, 32, outptr);
+#if RGB_PIXELSIZE == 4
+          if (num_cols > 48)
+            VEC_ST(rgb3, 48, outptr);
+#endif
+        }
+#if __BIG_ENDIAN__
+      }
+#endif
+    }
+  }
+}
+
+
+void jsimd_h2v2_merged_upsample_altivec (JDIMENSION output_width,
+                                         JSAMPIMAGE input_buf,
+                                         JDIMENSION in_row_group_ctr,
+                                         JSAMPARRAY output_buf)
+{
+  JSAMPROW inptr, outptr;
+
+  inptr = input_buf[0][in_row_group_ctr];
+  outptr = output_buf[0];
+
+  input_buf[0][in_row_group_ctr] = input_buf[0][in_row_group_ctr * 2];
+  jsimd_h2v1_merged_upsample_altivec(output_width, input_buf, in_row_group_ctr,
+                                     output_buf);
+
+  input_buf[0][in_row_group_ctr] = input_buf[0][in_row_group_ctr * 2 + 1];
+  output_buf[0] = output_buf[1];
+  jsimd_h2v1_merged_upsample_altivec(output_width, input_buf, in_row_group_ctr,
+                                     output_buf);
+
+  input_buf[0][in_row_group_ctr] = inptr;
+  output_buf[0] = outptr;
+}
diff --git a/simd/jdsample-altivec.c b/simd/jdsample-altivec.c
new file mode 100644
index 0000000..6b77d04
--- /dev/null
+++ b/simd/jdsample-altivec.c
@@ -0,0 +1,392 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2015, 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
+ * 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.
+ */
+
+/* CHROMA UPSAMPLING */
+
+#include "jsimd_altivec.h"
+
+
+void
+jsimd_h2v1_fancy_upsample_altivec (int max_v_samp_factor,
+                                   JDIMENSION downsampled_width,
+                                   JSAMPARRAY input_data,
+                                   JSAMPARRAY *output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  JSAMPROW inptr, outptr;
+  int inrow, incol;
+
+  __vector unsigned char this0, last0, p_last0, next0 = {0}, p_next0,
+    out;
+  __vector short this0e, this0o, this0l, this0h, last0l, last0h,
+    next0l, next0h, outle, outhe, outlo, outho;
+
+  /* Constants */
+  __vector unsigned char pb_zero = { __16X(0) }, pb_three = { __16X(3) },
+    last_index_col0 = {0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14},
+    last_index = {15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30},
+    next_index = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},
+    next_index_lastcol = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15},
+#if __BIG_ENDIAN__
+    merge_pack_index = {1,17,3,19,5,21,7,23,9,25,11,27,13,29,15,31};
+#else
+    merge_pack_index = {0,16,2,18,4,20,6,22,8,24,10,26,12,28,14,30};
+#endif
+  __vector short pw_one = { __8X(1) }, pw_two = { __8X(2) };
+
+  for (inrow = 0; inrow < max_v_samp_factor; inrow++) {
+    inptr = input_data[inrow];
+    outptr = output_data[inrow];
+
+    if (downsampled_width & 15)
+      inptr[downsampled_width] = inptr[downsampled_width - 1];
+
+    this0 = vec_ld(0, inptr);
+    p_last0 = vec_perm(this0, this0, last_index_col0);
+    last0 = this0;
+
+    for (incol = downsampled_width; incol > 0;
+         incol -= 16, inptr += 16, outptr += 32) {
+
+      if (downsampled_width - incol > 0) {
+        p_last0 = vec_perm(last0, this0, last_index);
+        last0 = this0;
+      }
+
+      if (incol <= 16)
+        p_next0 = vec_perm(this0, this0, next_index_lastcol);
+      else {
+        next0 = vec_ld(16, inptr);
+        p_next0 = vec_perm(this0, next0, next_index);
+      }
+
+      this0e = (__vector short)vec_mule(this0, pb_three);
+      this0o = (__vector short)vec_mulo(this0, pb_three);
+      this0l = vec_mergeh(this0e, this0o);
+      this0h = vec_mergel(this0e, this0o);
+
+      last0l = (__vector short)VEC_UNPACKHU(p_last0);
+      last0h = (__vector short)VEC_UNPACKLU(p_last0);
+      last0l = vec_add(last0l, pw_one);
+
+      next0l = (__vector short)VEC_UNPACKHU(p_next0);
+      next0h = (__vector short)VEC_UNPACKLU(p_next0);
+      next0l = vec_add(next0l, pw_two);
+
+      outle = vec_add(this0l, last0l);
+      outlo = vec_add(this0l, next0l);
+      outle = vec_sr(outle, (__vector unsigned short)pw_two);
+      outlo = vec_sr(outlo, (__vector unsigned short)pw_two);
+
+      out = vec_perm((__vector unsigned char)outle,
+                     (__vector unsigned char)outlo, merge_pack_index);
+      vec_st(out, 0, outptr);
+
+      if (incol > 8) {
+        last0h = vec_add(last0h, pw_one);
+        next0h = vec_add(next0h, pw_two);
+
+        outhe = vec_add(this0h, last0h);
+        outho = vec_add(this0h, next0h);
+        outhe = vec_sr(outhe, (__vector unsigned short)pw_two);
+        outho = vec_sr(outho, (__vector unsigned short)pw_two);
+
+        out = vec_perm((__vector unsigned char)outhe,
+                       (__vector unsigned char)outho, merge_pack_index);
+        vec_st(out, 16, outptr);
+      }
+
+      this0 = next0;
+    }
+  }
+}
+
+
+void
+jsimd_h2v2_fancy_upsample_altivec (int max_v_samp_factor,
+                                   JDIMENSION downsampled_width,
+                                   JSAMPARRAY input_data,
+                                   JSAMPARRAY *output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  JSAMPROW inptr_1, inptr0, inptr1, outptr0, outptr1;
+  int inrow, outrow, incol;
+
+  __vector unsigned char this_1, this0, this1, out;
+  __vector short this_1l, this_1h, this0l, this0h, this1l, this1h,
+    lastcolsum_1h, lastcolsum1h,
+    p_lastcolsum_1l, p_lastcolsum_1h, p_lastcolsum1l, p_lastcolsum1h,
+    thiscolsum_1l, thiscolsum_1h, thiscolsum1l, thiscolsum1h,
+    nextcolsum_1l = {0}, nextcolsum_1h = {0},
+    nextcolsum1l = {0}, nextcolsum1h = {0},
+    p_nextcolsum_1l, p_nextcolsum_1h, p_nextcolsum1l, p_nextcolsum1h,
+    tmpl, tmph, outle, outhe, outlo, outho;
+
+  /* Constants */
+  __vector unsigned char pb_zero = { __16X(0) },
+    last_index_col0 = {0,1,0,1,2,3,4,5,6,7,8,9,10,11,12,13},
+    last_index={14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29},
+    next_index = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17},
+    next_index_lastcol = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,15},
+#if __BIG_ENDIAN__
+    merge_pack_index = {1,17,3,19,5,21,7,23,9,25,11,27,13,29,15,31};
+#else
+    merge_pack_index = {0,16,2,18,4,20,6,22,8,24,10,26,12,28,14,30};
+#endif
+  __vector short pw_zero = { __8X(0) }, pw_three = { __8X(3) },
+    pw_seven = { __8X(7) }, pw_eight = { __8X(8) };
+  __vector unsigned short pw_four = { __8X(4) };
+
+  for (inrow = 0, outrow = 0; outrow < max_v_samp_factor; inrow++) {
+
+    inptr_1 = input_data[inrow - 1];
+    inptr0 = input_data[inrow];
+    inptr1 = input_data[inrow + 1];
+    outptr0 = output_data[outrow++];
+    outptr1 = output_data[outrow++];
+
+    if (downsampled_width & 15) {
+      inptr_1[downsampled_width] = inptr_1[downsampled_width - 1];
+      inptr0[downsampled_width] = inptr0[downsampled_width - 1];
+      inptr1[downsampled_width] = inptr1[downsampled_width - 1];
+    }
+
+    this0 = vec_ld(0, inptr0);
+    this0l = (__vector short)VEC_UNPACKHU(this0);
+    this0h = (__vector short)VEC_UNPACKLU(this0);
+    this0l = vec_mladd(this0l, pw_three, pw_zero);
+    this0h = vec_mladd(this0h, pw_three, pw_zero);
+
+    this_1 = vec_ld(0, inptr_1);
+    this_1l = (__vector short)VEC_UNPACKHU(this_1);
+    this_1h = (__vector short)VEC_UNPACKLU(this_1);
+    thiscolsum_1l = vec_add(this0l, this_1l);
+    thiscolsum_1h = vec_add(this0h, this_1h);
+    lastcolsum_1h = thiscolsum_1h;
+    p_lastcolsum_1l = vec_perm(thiscolsum_1l, thiscolsum_1l, last_index_col0);
+    p_lastcolsum_1h = vec_perm(thiscolsum_1l, thiscolsum_1h, last_index);
+
+    this1 = vec_ld(0, inptr1);
+    this1l = (__vector short)VEC_UNPACKHU(this1);
+    this1h = (__vector short)VEC_UNPACKLU(this1);
+    thiscolsum1l = vec_add(this0l, this1l);
+    thiscolsum1h = vec_add(this0h, this1h);
+    lastcolsum1h = thiscolsum1h;
+    p_lastcolsum1l = vec_perm(thiscolsum1l, thiscolsum1l, last_index_col0);
+    p_lastcolsum1h = vec_perm(thiscolsum1l, thiscolsum1h, last_index);
+
+    for (incol = downsampled_width; incol > 0;
+         incol -= 16, inptr_1 += 16, inptr0 += 16, inptr1 += 16,
+         outptr0 += 32, outptr1 += 32) {
+
+      if (downsampled_width - incol > 0) {
+        p_lastcolsum_1l = vec_perm(lastcolsum_1h, thiscolsum_1l, last_index);
+        p_lastcolsum_1h = vec_perm(thiscolsum_1l, thiscolsum_1h, last_index);
+        p_lastcolsum1l = vec_perm(lastcolsum1h, thiscolsum1l, last_index);
+        p_lastcolsum1h = vec_perm(thiscolsum1l, thiscolsum1h, last_index);
+        lastcolsum_1h = thiscolsum_1h;  lastcolsum1h = thiscolsum1h;
+      }
+
+      if (incol <= 16) {
+        p_nextcolsum_1l = vec_perm(thiscolsum_1l, thiscolsum_1h, next_index);
+        p_nextcolsum_1h = vec_perm(thiscolsum_1h, thiscolsum_1h,
+                                   next_index_lastcol);
+        p_nextcolsum1l = vec_perm(thiscolsum1l, thiscolsum1h, next_index);
+        p_nextcolsum1h = vec_perm(thiscolsum1h, thiscolsum1h,
+                                  next_index_lastcol);
+      } else {
+        this0 = vec_ld(16, inptr0);
+        this0l = (__vector short)VEC_UNPACKHU(this0);
+        this0h = (__vector short)VEC_UNPACKLU(this0);
+        this0l = vec_mladd(this0l, pw_three, pw_zero);
+        this0h = vec_mladd(this0h, pw_three, pw_zero);
+
+        this_1 = vec_ld(16, inptr_1);
+        this_1l = (__vector short)VEC_UNPACKHU(this_1);
+        this_1h = (__vector short)VEC_UNPACKLU(this_1);
+        nextcolsum_1l = vec_add(this0l, this_1l);
+        nextcolsum_1h = vec_add(this0h, this_1h);
+        p_nextcolsum_1l = vec_perm(thiscolsum_1l, thiscolsum_1h, next_index);
+        p_nextcolsum_1h = vec_perm(thiscolsum_1h, nextcolsum_1l, next_index);
+
+        this1 = vec_ld(16, inptr1);
+        this1l = (__vector short)VEC_UNPACKHU(this1);
+        this1h = (__vector short)VEC_UNPACKLU(this1);
+        nextcolsum1l = vec_add(this0l, this1l);
+        nextcolsum1h = vec_add(this0h, this1h);
+        p_nextcolsum1l = vec_perm(thiscolsum1l, thiscolsum1h, next_index);
+        p_nextcolsum1h = vec_perm(thiscolsum1h, nextcolsum1l, next_index);
+      }
+
+      /* Process the upper row */
+
+      tmpl = vec_mladd(thiscolsum_1l, pw_three, pw_zero);
+      outle = vec_add(tmpl, p_lastcolsum_1l);
+      outle = vec_add(outle, pw_eight);
+      outle = vec_sr(outle, pw_four);
+
+      outlo = vec_add(tmpl, p_nextcolsum_1l);
+      outlo = vec_add(outlo, pw_seven);
+      outlo = vec_sr(outlo, pw_four);
+
+      out = vec_perm((__vector unsigned char)outle,
+                     (__vector unsigned char)outlo, merge_pack_index);
+      vec_st(out, 0, outptr0);
+
+      if (incol > 8) {
+        tmph = vec_mladd(thiscolsum_1h, pw_three, pw_zero);
+        outhe = vec_add(tmph, p_lastcolsum_1h);
+        outhe = vec_add(outhe, pw_eight);
+        outhe = vec_sr(outhe, pw_four);
+
+        outho = vec_add(tmph, p_nextcolsum_1h);
+        outho = vec_add(outho, pw_seven);
+        outho = vec_sr(outho, pw_four);
+
+        out = vec_perm((__vector unsigned char)outhe,
+                       (__vector unsigned char)outho, merge_pack_index);
+        vec_st(out, 16, outptr0);
+      }
+
+      /* Process the lower row */
+
+      tmpl = vec_mladd(thiscolsum1l, pw_three, pw_zero);
+      outle = vec_add(tmpl, p_lastcolsum1l);
+      outle = vec_add(outle, pw_eight);
+      outle = vec_sr(outle, pw_four);
+
+      outlo = vec_add(tmpl, p_nextcolsum1l);
+      outlo = vec_add(outlo, pw_seven);
+      outlo = vec_sr(outlo, pw_four);
+
+      out = vec_perm((__vector unsigned char)outle,
+                     (__vector unsigned char)outlo, merge_pack_index);
+      vec_st(out, 0, outptr1);
+
+      if (incol > 8) {
+        tmph = vec_mladd(thiscolsum1h, pw_three, pw_zero);
+        outhe = vec_add(tmph, p_lastcolsum1h);
+        outhe = vec_add(outhe, pw_eight);
+        outhe = vec_sr(outhe, pw_four);
+
+        outho = vec_add(tmph, p_nextcolsum1h);
+        outho = vec_add(outho, pw_seven);
+        outho = vec_sr(outho, pw_four);
+
+        out = vec_perm((__vector unsigned char)outhe,
+                       (__vector unsigned char)outho, merge_pack_index);
+        vec_st(out, 16, outptr1);
+      }
+
+      thiscolsum_1l = nextcolsum_1l;  thiscolsum_1h = nextcolsum_1h;
+      thiscolsum1l = nextcolsum1l;  thiscolsum1h = nextcolsum1h;
+    }
+  }
+}
+
+
+/* These are rarely used (mainly just for decompressing YCCK images) */
+
+void
+jsimd_h2v1_upsample_altivec (int max_v_samp_factor,
+                             JDIMENSION output_width,
+                             JSAMPARRAY input_data,
+                             JSAMPARRAY * output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  JSAMPROW inptr, outptr;
+  int inrow, incol;
+
+  __vector unsigned char in, inl, inh;
+
+  for (inrow = 0; inrow < max_v_samp_factor; inrow++) {
+    inptr = input_data[inrow];
+    outptr = output_data[inrow];
+
+    for (incol = (output_width + 31) & (~31); incol > 0;
+         incol -= 64, inptr += 32, outptr += 64) {
+
+      in = vec_ld(0, inptr);
+      inl = vec_mergeh(in, in);
+      inh = vec_mergel(in, in);
+
+      vec_st(inl, 0, outptr);
+      vec_st(inh, 16, outptr);
+
+      if (incol > 32) {
+        in = vec_ld(16, inptr);
+        inl = vec_mergeh(in, in);
+        inh = vec_mergel(in, in);
+
+        vec_st(inl, 32, outptr);
+        vec_st(inh, 48, outptr);
+      }
+    }
+  }
+}
+
+
+void
+jsimd_h2v2_upsample_altivec (int max_v_samp_factor,
+                             JDIMENSION output_width,
+                             JSAMPARRAY input_data,
+                             JSAMPARRAY * output_data_ptr)
+{
+  JSAMPARRAY output_data = *output_data_ptr;
+  JSAMPROW inptr, outptr0, outptr1;
+  int inrow, outrow, incol;
+
+  __vector unsigned char in, inl, inh;
+
+  for (inrow = 0, outrow = 0; outrow < max_v_samp_factor; inrow++) {
+
+    inptr = input_data[inrow];
+    outptr0 = output_data[outrow++];
+    outptr1 = output_data[outrow++];
+
+    for (incol = (output_width + 31) & (~31); incol > 0;
+         incol -= 64, inptr += 32, outptr0 += 64, outptr1 += 64) {
+
+      in = vec_ld(0, inptr);
+      inl = vec_mergeh(in, in);
+      inh = vec_mergel(in, in);
+
+      vec_st(inl, 0, outptr0);
+      vec_st(inl, 0, outptr1);
+
+      vec_st(inh, 16, outptr0);
+      vec_st(inh, 16, outptr1);
+
+      if (incol > 32) {
+        in = vec_ld(16, inptr);
+        inl = vec_mergeh(in, in);
+        inh = vec_mergel(in, in);
+
+        vec_st(inl, 32, outptr0);
+        vec_st(inl, 32, outptr1);
+
+        vec_st(inh, 48, outptr0);
+        vec_st(inh, 48, outptr1);
+      }
+    }
+  }
+}
diff --git a/simd/jfdctfst-altivec.c b/simd/jfdctfst-altivec.c
new file mode 100644
index 0000000..c4cc26e
--- /dev/null
+++ b/simd/jfdctfst-altivec.c
@@ -0,0 +1,156 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014, 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
+ * 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.
+ */
+
+/* FAST INTEGER FORWARD DCT
+ *
+ * This is similar to the SSE2 implementation, except that we left-shift the
+ * constants by 1 less bit (the -1 in CONST_SHIFT.)  This is because
+ * vec_madds(arg1, arg2, arg3) generates the 16-bit saturated sum of:
+ *   the elements in arg3 + the most significant 17 bits of
+ *     (the elements in arg1 * the elements in arg2).
+ */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_382 98   /* FIX(0.382683433) */
+#define F_0_541 139  /* FIX(0.541196100) */
+#define F_0_707 181  /* FIX(0.707106781) */
+#define F_1_306 334  /* FIX(1.306562965) */
+
+#define CONST_BITS 8
+#define PRE_MULTIPLY_SCALE_BITS 2
+#define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS - 1)
+
+
+#define DO_FDCT()  \
+{  \
+  /* Even part */  \
+  \
+  tmp10 = vec_add(tmp0, tmp3);  \
+  tmp13 = vec_sub(tmp0, tmp3);  \
+  tmp11 = vec_add(tmp1, tmp2);  \
+  tmp12 = vec_sub(tmp1, tmp2);  \
+  \
+  out0  = vec_add(tmp10, tmp11);  \
+  out4  = vec_sub(tmp10, tmp11);  \
+  \
+  z1 = vec_add(tmp12, tmp13);  \
+  z1 = vec_sl(z1, pre_multiply_scale_bits);  \
+  z1 = vec_madds(z1, pw_0707, pw_zero);  \
+  \
+  out2 = vec_add(tmp13, z1);  \
+  out6 = vec_sub(tmp13, z1);  \
+  \
+  /* Odd part */  \
+  \
+  tmp10 = vec_add(tmp4, tmp5);  \
+  tmp11 = vec_add(tmp5, tmp6);  \
+  tmp12 = vec_add(tmp6, tmp7);  \
+  \
+  tmp10 = vec_sl(tmp10, pre_multiply_scale_bits);  \
+  tmp12 = vec_sl(tmp12, pre_multiply_scale_bits);  \
+  z5 = vec_sub(tmp10, tmp12);  \
+  z5 = vec_madds(z5, pw_0382, pw_zero);  \
+  \
+  z2 = vec_madds(tmp10, pw_0541, z5);  \
+  z4 = vec_madds(tmp12, pw_1306, z5);  \
+  \
+  tmp11 = vec_sl(tmp11, pre_multiply_scale_bits);  \
+  z3 = vec_madds(tmp11, pw_0707, pw_zero);  \
+  \
+  z11 = vec_add(tmp7, z3);  \
+  z13 = vec_sub(tmp7, z3);  \
+  \
+  out5 = vec_add(z13, z2);  \
+  out3 = vec_sub(z13, z2);  \
+  out1 = vec_add(z11, z4);  \
+  out7 = vec_sub(z11, z4);  \
+}
+
+
+void
+jsimd_fdct_ifast_altivec (DCTELEM *data)
+{
+  __vector short row0, row1, row2, row3, row4, row5, row6, row7,
+    col0, col1, col2, col3, col4, col5, col6, col7,
+    tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp10, tmp11, tmp12, tmp13,
+    z1, z2, z3, z4, z5, z11, z13,
+    out0, out1, out2, out3, out4, out5, out6, out7;
+
+  /* Constants */
+  __vector short pw_zero = { __8X(0) },
+    pw_0382 = { __8X(F_0_382 << CONST_SHIFT) },
+    pw_0541 = { __8X(F_0_541 << CONST_SHIFT) },
+    pw_0707 = { __8X(F_0_707 << CONST_SHIFT) },
+    pw_1306 = { __8X(F_1_306 << CONST_SHIFT) };
+  __vector unsigned short
+    pre_multiply_scale_bits = { __8X(PRE_MULTIPLY_SCALE_BITS) };
+
+  /* Pass 1: process rows */
+
+  row0 = vec_ld(0, data);
+  row1 = vec_ld(16, data);
+  row2 = vec_ld(32, data);
+  row3 = vec_ld(48, data);
+  row4 = vec_ld(64, data);
+  row5 = vec_ld(80, data);
+  row6 = vec_ld(96, data);
+  row7 = vec_ld(112, data);
+
+  TRANSPOSE(row, col);
+
+  tmp0 = vec_add(col0, col7);
+  tmp7 = vec_sub(col0, col7);
+  tmp1 = vec_add(col1, col6);
+  tmp6 = vec_sub(col1, col6);
+  tmp2 = vec_add(col2, col5);
+  tmp5 = vec_sub(col2, col5);
+  tmp3 = vec_add(col3, col4);
+  tmp4 = vec_sub(col3, col4);
+
+  DO_FDCT();
+
+  /* Pass 2: process columns */
+
+  TRANSPOSE(out, row);
+
+  tmp0 = vec_add(row0, row7);
+  tmp7 = vec_sub(row0, row7);
+  tmp1 = vec_add(row1, row6);
+  tmp6 = vec_sub(row1, row6);
+  tmp2 = vec_add(row2, row5);
+  tmp5 = vec_sub(row2, row5);
+  tmp3 = vec_add(row3, row4);
+  tmp4 = vec_sub(row3, row4);
+
+  DO_FDCT();
+
+  vec_st(out0, 0, data);
+  vec_st(out1, 16, data);
+  vec_st(out2, 32, data);
+  vec_st(out3, 48, data);
+  vec_st(out4, 64, data);
+  vec_st(out5, 80, data);
+  vec_st(out6, 96, data);
+  vec_st(out7, 112, data);
+}
diff --git a/simd/jfdctint-altivec.c b/simd/jfdctint-altivec.c
new file mode 100644
index 0000000..c13850a
--- /dev/null
+++ b/simd/jfdctint-altivec.c
@@ -0,0 +1,262 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014, 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
+ * 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.
+ */
+
+/* SLOW INTEGER FORWARD DCT */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_298 2446   /* FIX(0.298631336) */
+#define F_0_390 3196   /* FIX(0.390180644) */
+#define F_0_541 4433   /* FIX(0.541196100) */
+#define F_0_765 6270   /* FIX(0.765366865) */
+#define F_0_899 7373   /* FIX(0.899976223) */
+#define F_1_175 9633   /* FIX(1.175875602) */
+#define F_1_501 12299  /* FIX(1.501321110) */
+#define F_1_847 15137  /* FIX(1.847759065) */
+#define F_1_961 16069  /* FIX(1.961570560) */
+#define F_2_053 16819  /* FIX(2.053119869) */
+#define F_2_562 20995  /* FIX(2.562915447) */
+#define F_3_072 25172  /* FIX(3.072711026) */
+
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#define DESCALE_P1 (CONST_BITS - PASS1_BITS)
+#define DESCALE_P2 (CONST_BITS + PASS1_BITS)
+
+
+#define DO_FDCT_COMMON(PASS)  \
+{  \
+  /* (Original)  \
+   * z1 = (tmp12 + tmp13) * 0.541196100;  \
+   * data2 = z1 + tmp13 * 0.765366865;  \
+   * data6 = z1 + tmp12 * -1.847759065;  \
+   *  \
+   * (This implementation)  \
+   * data2 = tmp13 * (0.541196100 + 0.765366865) + tmp12 * 0.541196100;  \
+   * data6 = tmp13 * 0.541196100 + tmp12 * (0.541196100 - 1.847759065);  \
+   */  \
+  \
+  tmp1312l = vec_mergeh(tmp13, tmp12);  \
+  tmp1312h = vec_mergel(tmp13, tmp12);  \
+  \
+  out2l = vec_msums(tmp1312l, pw_f130_f054, pd_descale_p##PASS);  \
+  out2h = vec_msums(tmp1312h, pw_f130_f054, pd_descale_p##PASS);  \
+  out6l = vec_msums(tmp1312l, pw_f054_mf130, pd_descale_p##PASS);  \
+  out6h = vec_msums(tmp1312h, pw_f054_mf130, pd_descale_p##PASS);  \
+  \
+  out2l = vec_sra(out2l, descale_p##PASS);  \
+  out2h = vec_sra(out2h, descale_p##PASS);  \
+  out6l = vec_sra(out6l, descale_p##PASS);  \
+  out6h = vec_sra(out6h, descale_p##PASS);  \
+  \
+  out2 = vec_pack(out2l, out2h);  \
+  out6 = vec_pack(out6l, out6h);  \
+  \
+  /* Odd part */  \
+  \
+  z3 = vec_add(tmp4, tmp6);  \
+  z4 = vec_add(tmp5, tmp7);  \
+  \
+  /* (Original)  \
+   * z5 = (z3 + z4) * 1.175875602;  \
+   * z3 = z3 * -1.961570560;  z4 = z4 * -0.390180644;  \
+   * z3 += z5;  z4 += z5;  \
+   *  \
+   * (This implementation)  \
+   * z3 = z3 * (1.175875602 - 1.961570560) + z4 * 1.175875602;  \
+   * z4 = z3 * 1.175875602 + z4 * (1.175875602 - 0.390180644);  \
+   */  \
+  \
+  z34l = vec_mergeh(z3, z4);  \
+  z34h = vec_mergel(z3, z4);  \
+  \
+  z3l = vec_msums(z34l, pw_mf078_f117, pd_descale_p##PASS);  \
+  z3h = vec_msums(z34h, pw_mf078_f117, pd_descale_p##PASS);  \
+  z4l = vec_msums(z34l, pw_f117_f078, pd_descale_p##PASS);  \
+  z4h = vec_msums(z34h, pw_f117_f078, pd_descale_p##PASS);  \
+  \
+  /* (Original)  \
+   * z1 = tmp4 + tmp7;  z2 = tmp5 + tmp6;  \
+   * tmp4 = tmp4 * 0.298631336;  tmp5 = tmp5 * 2.053119869;  \
+   * tmp6 = tmp6 * 3.072711026;  tmp7 = tmp7 * 1.501321110;  \
+   * z1 = z1 * -0.899976223;  z2 = z2 * -2.562915447;  \
+   * data7 = tmp4 + z1 + z3;  data5 = tmp5 + z2 + z4;  \
+   * data3 = tmp6 + z2 + z3;  data1 = tmp7 + z1 + z4;  \
+   *  \
+   * (This implementation)  \
+   * tmp4 = tmp4 * (0.298631336 - 0.899976223) + tmp7 * -0.899976223;  \
+   * tmp5 = tmp5 * (2.053119869 - 2.562915447) + tmp6 * -2.562915447;  \
+   * tmp6 = tmp5 * -2.562915447 + tmp6 * (3.072711026 - 2.562915447);  \
+   * tmp7 = tmp4 * -0.899976223 + tmp7 * (1.501321110 - 0.899976223);  \
+   * data7 = tmp4 + z3;  data5 = tmp5 + z4;  \
+   * data3 = tmp6 + z3;  data1 = tmp7 + z4;  \
+   */  \
+  \
+  tmp47l = vec_mergeh(tmp4, tmp7);  \
+  tmp47h = vec_mergel(tmp4, tmp7);  \
+  \
+  out7l = vec_msums(tmp47l, pw_mf060_mf089, z3l);  \
+  out7h = vec_msums(tmp47h, pw_mf060_mf089, z3h);  \
+  out1l = vec_msums(tmp47l, pw_mf089_f060, z4l);  \
+  out1h = vec_msums(tmp47h, pw_mf089_f060, z4h);  \
+  \
+  out7l = vec_sra(out7l, descale_p##PASS);  \
+  out7h = vec_sra(out7h, descale_p##PASS);  \
+  out1l = vec_sra(out1l, descale_p##PASS);  \
+  out1h = vec_sra(out1h, descale_p##PASS);  \
+  \
+  out7 = vec_pack(out7l, out7h);  \
+  out1 = vec_pack(out1l, out1h);  \
+  \
+  tmp56l = vec_mergeh(tmp5, tmp6);  \
+  tmp56h = vec_mergel(tmp5, tmp6);  \
+  \
+  out5l = vec_msums(tmp56l, pw_mf050_mf256, z4l);  \
+  out5h = vec_msums(tmp56h, pw_mf050_mf256, z4h);  \
+  out3l = vec_msums(tmp56l, pw_mf256_f050, z3l);  \
+  out3h = vec_msums(tmp56h, pw_mf256_f050, z3h);  \
+  \
+  out5l = vec_sra(out5l, descale_p##PASS);  \
+  out5h = vec_sra(out5h, descale_p##PASS);  \
+  out3l = vec_sra(out3l, descale_p##PASS);  \
+  out3h = vec_sra(out3h, descale_p##PASS);  \
+  \
+  out5 = vec_pack(out5l, out5h);  \
+  out3 = vec_pack(out3l, out3h);  \
+}
+
+#define DO_FDCT_PASS1()  \
+{  \
+  /* Even part */  \
+  \
+  tmp10 = vec_add(tmp0, tmp3);  \
+  tmp13 = vec_sub(tmp0, tmp3);  \
+  tmp11 = vec_add(tmp1, tmp2);  \
+  tmp12 = vec_sub(tmp1, tmp2);  \
+  \
+  out0  = vec_add(tmp10, tmp11);  \
+  out0  = vec_sl(out0, pass1_bits);  \
+  out4  = vec_sub(tmp10, tmp11);  \
+  out4  = vec_sl(out4, pass1_bits);  \
+  \
+  DO_FDCT_COMMON(1);  \
+}
+
+#define DO_FDCT_PASS2()  \
+{  \
+  /* Even part */  \
+  \
+  tmp10 = vec_add(tmp0, tmp3);  \
+  tmp13 = vec_sub(tmp0, tmp3);  \
+  tmp11 = vec_add(tmp1, tmp2);  \
+  tmp12 = vec_sub(tmp1, tmp2);  \
+  \
+  out0  = vec_add(tmp10, tmp11);  \
+  out0  = vec_add(out0, pw_descale_p2x);  \
+  out0  = vec_sra(out0, pass1_bits);  \
+  out4  = vec_sub(tmp10, tmp11);  \
+  out4  = vec_add(out4, pw_descale_p2x);  \
+  out4  = vec_sra(out4, pass1_bits);  \
+  \
+  DO_FDCT_COMMON(2);  \
+}
+
+
+void
+jsimd_fdct_islow_altivec (DCTELEM *data)
+{
+  __vector short row0, row1, row2, row3, row4, row5, row6, row7,
+    col0, col1, col2, col3, col4, col5, col6, col7,
+    tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp10, tmp11, tmp12, tmp13,
+    tmp47l, tmp47h, tmp56l, tmp56h, tmp1312l, tmp1312h,
+    z3, z4, z34l, z34h,
+    out0, out1, out2, out3, out4, out5, out6, out7;
+  __vector int z3l, z3h, z4l, z4h,
+    out1l, out1h, out2l, out2h, out3l, out3h, out5l, out5h, out6l, out6h,
+    out7l, out7h;
+
+  /* Constants */
+  __vector short
+    pw_f130_f054 = { __4X2(F_0_541 + F_0_765, F_0_541) },
+    pw_f054_mf130 = { __4X2(F_0_541, F_0_541 - F_1_847) },
+    pw_mf078_f117 = { __4X2(F_1_175 - F_1_961, F_1_175) },
+    pw_f117_f078 = { __4X2(F_1_175, F_1_175 - F_0_390) },
+    pw_mf060_mf089 = { __4X2(F_0_298 - F_0_899, -F_0_899) },
+    pw_mf089_f060 = { __4X2(-F_0_899, F_1_501 - F_0_899) },
+    pw_mf050_mf256 = { __4X2(F_2_053 - F_2_562, -F_2_562) },
+    pw_mf256_f050 = { __4X2(-F_2_562, F_3_072 - F_2_562) },
+    pw_descale_p2x = { __8X(1 << (PASS1_BITS - 1)) };
+  __vector unsigned short pass1_bits = { __8X(PASS1_BITS) };
+  __vector int pd_descale_p1 = { __4X(1 << (DESCALE_P1 - 1)) },
+    pd_descale_p2 = { __4X(1 << (DESCALE_P2 - 1)) };
+  __vector unsigned int descale_p1 = { __4X(DESCALE_P1) },
+    descale_p2 = { __4X(DESCALE_P2) };
+
+  /* Pass 1: process rows */
+
+  row0 = vec_ld(0, data);
+  row1 = vec_ld(16, data);
+  row2 = vec_ld(32, data);
+  row3 = vec_ld(48, data);
+  row4 = vec_ld(64, data);
+  row5 = vec_ld(80, data);
+  row6 = vec_ld(96, data);
+  row7 = vec_ld(112, data);
+
+  TRANSPOSE(row, col);
+
+  tmp0 = vec_add(col0, col7);
+  tmp7 = vec_sub(col0, col7);
+  tmp1 = vec_add(col1, col6);
+  tmp6 = vec_sub(col1, col6);
+  tmp2 = vec_add(col2, col5);
+  tmp5 = vec_sub(col2, col5);
+  tmp3 = vec_add(col3, col4);
+  tmp4 = vec_sub(col3, col4);
+
+  DO_FDCT_PASS1();
+
+  /* Pass 2: process columns */
+
+  TRANSPOSE(out, row);
+
+  tmp0 = vec_add(row0, row7);
+  tmp7 = vec_sub(row0, row7);
+  tmp1 = vec_add(row1, row6);
+  tmp6 = vec_sub(row1, row6);
+  tmp2 = vec_add(row2, row5);
+  tmp5 = vec_sub(row2, row5);
+  tmp3 = vec_add(row3, row4);
+  tmp4 = vec_sub(row3, row4);
+
+  DO_FDCT_PASS2();
+
+  vec_st(out0, 0, data);
+  vec_st(out1, 16, data);
+  vec_st(out2, 32, data);
+  vec_st(out3, 48, data);
+  vec_st(out4, 64, data);
+  vec_st(out5, 80, data);
+  vec_st(out6, 96, data);
+  vec_st(out7, 112, data);
+}
diff --git a/simd/jidctfst-altivec.c b/simd/jidctfst-altivec.c
new file mode 100644
index 0000000..fd7a2a3
--- /dev/null
+++ b/simd/jidctfst-altivec.c
@@ -0,0 +1,257 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, 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
+ * 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.
+ */
+
+/* FAST INTEGER INVERSE DCT
+ *
+ * This is similar to the SSE2 implementation, except that we left-shift the
+ * constants by 1 less bit (the -1 in CONST_SHIFT.)  This is because
+ * vec_madds(arg1, arg2, arg3) generates the 16-bit saturated sum of:
+ *   the elements in arg3 + the most significant 17 bits of
+ *     (the elements in arg1 * the elements in arg2).
+ */
+
+#include "jsimd_altivec.h"
+
+
+#define F_1_082 277              /* FIX(1.082392200) */
+#define F_1_414 362              /* FIX(1.414213562) */
+#define F_1_847 473              /* FIX(1.847759065) */
+#define F_2_613 669              /* FIX(2.613125930) */
+#define F_1_613 (F_2_613 - 256)  /* FIX(2.613125930) - FIX(1) */
+
+#define CONST_BITS 8
+#define PASS1_BITS 2
+#define PRE_MULTIPLY_SCALE_BITS 2
+#define CONST_SHIFT (16 - PRE_MULTIPLY_SCALE_BITS - CONST_BITS - 1)
+
+
+#define DO_IDCT(in)  \
+{  \
+  /* Even part */  \
+  \
+  tmp10 = vec_add(in##0, in##4);  \
+  tmp11 = vec_sub(in##0, in##4);  \
+  tmp13 = vec_add(in##2, in##6);  \
+  \
+  tmp12 = vec_sub(in##2, in##6);  \
+  tmp12 = vec_sl(tmp12, pre_multiply_scale_bits);  \
+  tmp12 = vec_madds(tmp12, pw_F1414, pw_zero);  \
+  tmp12 = vec_sub(tmp12, tmp13);  \
+  \
+  tmp0 = vec_add(tmp10, tmp13);  \
+  tmp3 = vec_sub(tmp10, tmp13);  \
+  tmp1 = vec_add(tmp11, tmp12);  \
+  tmp2 = vec_sub(tmp11, tmp12);  \
+  \
+  /* Odd part */  \
+  \
+  z13 = vec_add(in##5, in##3);  \
+  z10 = vec_sub(in##5, in##3);  \
+  z10s = vec_sl(z10, pre_multiply_scale_bits);  \
+  z11 = vec_add(in##1, in##7);  \
+  z12s = vec_sub(in##1, in##7);  \
+  z12s = vec_sl(z12s, pre_multiply_scale_bits);  \
+  \
+  tmp11 = vec_sub(z11, z13);  \
+  tmp11 = vec_sl(tmp11, pre_multiply_scale_bits);  \
+  tmp11 = vec_madds(tmp11, pw_F1414, pw_zero);  \
+  \
+  tmp7 = vec_add(z11, z13);  \
+  \
+  /* To avoid overflow...  \
+   *  \
+   * (Original)  \
+   * tmp12 = -2.613125930 * z10 + z5;  \
+   *  \
+   * (This implementation)  \
+   * tmp12 = (-1.613125930 - 1) * z10 + z5;  \
+   *       = -1.613125930 * z10 - z10 + z5;  \
+   */  \
+  \
+  z5 = vec_add(z10s, z12s);  \
+  z5 = vec_madds(z5, pw_F1847, pw_zero);  \
+  \
+  tmp10 = vec_madds(z12s, pw_F1082, pw_zero);  \
+  tmp10 = vec_sub(tmp10, z5);  \
+  tmp12 = vec_madds(z10s, pw_MF1613, z5);  \
+  tmp12 = vec_sub(tmp12, z10);  \
+  \
+  tmp6 = vec_sub(tmp12, tmp7);  \
+  tmp5 = vec_sub(tmp11, tmp6);  \
+  tmp4 = vec_add(tmp10, tmp5);  \
+  \
+  out0 = vec_add(tmp0, tmp7);  \
+  out1 = vec_add(tmp1, tmp6);  \
+  out2 = vec_add(tmp2, tmp5);  \
+  out3 = vec_sub(tmp3, tmp4);  \
+  out4 = vec_add(tmp3, tmp4);  \
+  out5 = vec_sub(tmp2, tmp5);  \
+  out6 = vec_sub(tmp1, tmp6);  \
+  out7 = vec_sub(tmp0, tmp7);  \
+}
+
+
+void
+jsimd_idct_ifast_altivec (void * dct_table_, JCOEFPTR coef_block,
+                          JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  short *dct_table = (short *)dct_table_;
+  int *outptr;
+
+  __vector short row0, row1, row2, row3, row4, row5, row6, row7,
+    col0, col1, col2, col3, col4, col5, col6, col7,
+    quant0, quant1, quant2, quant3, quant4, quant5, quant6, quant7,
+    tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp10, tmp11, tmp12, tmp13,
+    z5, z10, z10s, z11, z12s, z13,
+    out0, out1, out2, out3, out4, out5, out6, out7;
+  __vector signed char outb;
+
+  /* Constants */
+  __vector short pw_zero = { __8X(0) },
+    pw_F1414 = { __8X(F_1_414 << CONST_SHIFT) },
+    pw_F1847 = { __8X(F_1_847 << CONST_SHIFT) },
+    pw_MF1613 = { __8X(-F_1_613 << CONST_SHIFT) },
+    pw_F1082 = { __8X(F_1_082 << CONST_SHIFT) };
+  __vector unsigned short
+    pre_multiply_scale_bits = { __8X(PRE_MULTIPLY_SCALE_BITS) },
+    pass1_bits3 = { __8X(PASS1_BITS + 3) };
+  __vector signed char pb_centerjsamp = { __16X(CENTERJSAMPLE) };
+
+  /* Pass 1: process columns */
+
+  col0 = vec_ld(0, coef_block);
+  col1 = vec_ld(16, coef_block);
+  col2 = vec_ld(32, coef_block);
+  col3 = vec_ld(48, coef_block);
+  col4 = vec_ld(64, coef_block);
+  col5 = vec_ld(80, coef_block);
+  col6 = vec_ld(96, coef_block);
+  col7 = vec_ld(112, coef_block);
+
+  tmp1 = vec_or(col1, col2);
+  tmp2 = vec_or(col3, col4);
+  tmp1 = vec_or(tmp1, tmp2);
+  tmp3 = vec_or(col5, col6);
+  tmp3 = vec_or(tmp3, col7);
+  tmp1 = vec_or(tmp1, tmp3);
+
+  quant0 = vec_ld(0, dct_table);
+  col0 = vec_mladd(col0, quant0, pw_zero);
+
+  if (vec_all_eq(tmp1, pw_zero)) {
+    /* AC terms all zero */
+
+    row0 = vec_splat(col0, 0);
+    row1 = vec_splat(col0, 1);
+    row2 = vec_splat(col0, 2);
+    row3 = vec_splat(col0, 3);
+    row4 = vec_splat(col0, 4);
+    row5 = vec_splat(col0, 5);
+    row6 = vec_splat(col0, 6);
+    row7 = vec_splat(col0, 7);
+
+  } else {
+
+    quant1 = vec_ld(16, dct_table);
+    quant2 = vec_ld(32, dct_table);
+    quant3 = vec_ld(48, dct_table);
+    quant4 = vec_ld(64, dct_table);
+    quant5 = vec_ld(80, dct_table);
+    quant6 = vec_ld(96, dct_table);
+    quant7 = vec_ld(112, dct_table);
+
+    col1 = vec_mladd(col1, quant1, pw_zero);
+    col2 = vec_mladd(col2, quant2, pw_zero);
+    col3 = vec_mladd(col3, quant3, pw_zero);
+    col4 = vec_mladd(col4, quant4, pw_zero);
+    col5 = vec_mladd(col5, quant5, pw_zero);
+    col6 = vec_mladd(col6, quant6, pw_zero);
+    col7 = vec_mladd(col7, quant7, pw_zero);
+
+    DO_IDCT(col);
+
+    TRANSPOSE(out, row);
+  }
+
+  /* Pass 2: process rows */
+
+  DO_IDCT(row);
+
+  out0 = vec_sra(out0, pass1_bits3);
+  out1 = vec_sra(out1, pass1_bits3);
+  out2 = vec_sra(out2, pass1_bits3);
+  out3 = vec_sra(out3, pass1_bits3);
+  out4 = vec_sra(out4, pass1_bits3);
+  out5 = vec_sra(out5, pass1_bits3);
+  out6 = vec_sra(out6, pass1_bits3);
+  out7 = vec_sra(out7, pass1_bits3);
+
+  TRANSPOSE(out, col);
+
+  outb = vec_packs(col0, col0);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[0] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col1, col1);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[1] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col2, col2);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[2] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col3, col3);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[3] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col4, col4);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[4] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col5, col5);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[5] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col6, col6);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[6] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col7, col7);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[7] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+}
diff --git a/simd/jidctint-altivec.c b/simd/jidctint-altivec.c
new file mode 100644
index 0000000..7f0f8d0
--- /dev/null
+++ b/simd/jidctint-altivec.c
@@ -0,0 +1,359 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, 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
+ * 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.
+ */
+
+/* SLOW INTEGER INVERSE DCT */
+
+#include "jsimd_altivec.h"
+
+
+#define F_0_298 2446   /* FIX(0.298631336) */
+#define F_0_390 3196   /* FIX(0.390180644) */
+#define F_0_541 4433   /* FIX(0.541196100) */
+#define F_0_765 6270   /* FIX(0.765366865) */
+#define F_0_899 7373   /* FIX(0.899976223) */
+#define F_1_175 9633   /* FIX(1.175875602) */
+#define F_1_501 12299  /* FIX(1.501321110) */
+#define F_1_847 15137  /* FIX(1.847759065) */
+#define F_1_961 16069  /* FIX(1.961570560) */
+#define F_2_053 16819  /* FIX(2.053119869) */
+#define F_2_562 20995  /* FIX(2.562915447) */
+#define F_3_072 25172  /* FIX(3.072711026) */
+
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#define DESCALE_P1 (CONST_BITS - PASS1_BITS)
+#define DESCALE_P2 (CONST_BITS + PASS1_BITS + 3)
+
+
+#define DO_IDCT(in, PASS)  \
+{  \
+  /* Even part  \
+   *  \
+   * (Original)  \
+   * z1 = (z2 + z3) * 0.541196100;  \
+   * tmp2 = z1 + z3 * -1.847759065;  \
+   * tmp3 = z1 + z2 * 0.765366865;  \
+   *  \
+   * (This implementation)  \
+   * tmp2 = z2 * 0.541196100 + z3 * (0.541196100 - 1.847759065);  \
+   * tmp3 = z2 * (0.541196100 + 0.765366865) + z3 * 0.541196100;  \
+   */  \
+  \
+  in##26l = vec_mergeh(in##2, in##6);  \
+  in##26h = vec_mergel(in##2, in##6);  \
+  \
+  tmp3l = vec_msums(in##26l, pw_f130_f054, pd_zero);  \
+  tmp3h = vec_msums(in##26h, pw_f130_f054, pd_zero);  \
+  tmp2l = vec_msums(in##26l, pw_f054_mf130, pd_zero);  \
+  tmp2h = vec_msums(in##26h, pw_f054_mf130, pd_zero);  \
+  \
+  tmp0 = vec_add(in##0, in##4);  \
+  tmp1 = vec_sub(in##0, in##4);  \
+  \
+  tmp0l = vec_unpackh(tmp0);  \
+  tmp0h = vec_unpackl(tmp0);  \
+  tmp0l = vec_sl(tmp0l, const_bits);  \
+  tmp0h = vec_sl(tmp0h, const_bits);  \
+  tmp0l = vec_add(tmp0l, pd_descale_p##PASS);  \
+  tmp0h = vec_add(tmp0h, pd_descale_p##PASS);  \
+  \
+  tmp10l = vec_add(tmp0l, tmp3l);  \
+  tmp10h = vec_add(tmp0h, tmp3h);  \
+  tmp13l = vec_sub(tmp0l, tmp3l);  \
+  tmp13h = vec_sub(tmp0h, tmp3h);  \
+  \
+  tmp1l = vec_unpackh(tmp1);  \
+  tmp1h = vec_unpackl(tmp1);  \
+  tmp1l = vec_sl(tmp1l, const_bits);  \
+  tmp1h = vec_sl(tmp1h, const_bits);  \
+  tmp1l = vec_add(tmp1l, pd_descale_p##PASS);  \
+  tmp1h = vec_add(tmp1h, pd_descale_p##PASS);  \
+  \
+  tmp11l = vec_add(tmp1l, tmp2l);  \
+  tmp11h = vec_add(tmp1h, tmp2h);  \
+  tmp12l = vec_sub(tmp1l, tmp2l);  \
+  tmp12h = vec_sub(tmp1h, tmp2h);  \
+  \
+  /* Odd part */  \
+  \
+  z3 = vec_add(in##3, in##7);  \
+  z4 = vec_add(in##1, in##5);  \
+  \
+  /* (Original)  \
+   * z5 = (z3 + z4) * 1.175875602;  \
+   * z3 = z3 * -1.961570560;  z4 = z4 * -0.390180644;  \
+   * z3 += z5;  z4 += z5;  \
+   *  \
+   * (This implementation)  \
+   * z3 = z3 * (1.175875602 - 1.961570560) + z4 * 1.175875602;  \
+   * z4 = z3 * 1.175875602 + z4 * (1.175875602 - 0.390180644);  \
+   */  \
+  \
+  z34l = vec_mergeh(z3, z4);  \
+  z34h = vec_mergel(z3, z4);  \
+  \
+  z3l = vec_msums(z34l, pw_mf078_f117, pd_zero);  \
+  z3h = vec_msums(z34h, pw_mf078_f117, pd_zero);  \
+  z4l = vec_msums(z34l, pw_f117_f078, pd_zero);  \
+  z4h = vec_msums(z34h, pw_f117_f078, pd_zero);  \
+  \
+  /* (Original)  \
+   * z1 = tmp0 + tmp3;  z2 = tmp1 + tmp2;  \
+   * tmp0 = tmp0 * 0.298631336;  tmp1 = tmp1 * 2.053119869;  \
+   * tmp2 = tmp2 * 3.072711026;  tmp3 = tmp3 * 1.501321110;  \
+   * z1 = z1 * -0.899976223;  z2 = z2 * -2.562915447;  \
+   * tmp0 += z1 + z3;  tmp1 += z2 + z4;  \
+   * tmp2 += z2 + z3;  tmp3 += z1 + z4;  \
+   *  \
+   * (This implementation)  \
+   * tmp0 = tmp0 * (0.298631336 - 0.899976223) + tmp3 * -0.899976223;  \
+   * tmp1 = tmp1 * (2.053119869 - 2.562915447) + tmp2 * -2.562915447;  \
+   * tmp2 = tmp1 * -2.562915447 + tmp2 * (3.072711026 - 2.562915447);  \
+   * tmp3 = tmp0 * -0.899976223 + tmp3 * (1.501321110 - 0.899976223);  \
+   * tmp0 += z3;  tmp1 += z4;  \
+   * tmp2 += z3;  tmp3 += z4;  \
+   */  \
+  \
+  in##71l = vec_mergeh(in##7, in##1);  \
+  in##71h = vec_mergel(in##7, in##1);  \
+  \
+  tmp0l = vec_msums(in##71l, pw_mf060_mf089, z3l);  \
+  tmp0h = vec_msums(in##71h, pw_mf060_mf089, z3h);  \
+  tmp3l = vec_msums(in##71l, pw_mf089_f060, z4l);  \
+  tmp3h = vec_msums(in##71h, pw_mf089_f060, z4h);  \
+  \
+  in##53l = vec_mergeh(in##5, in##3);  \
+  in##53h = vec_mergel(in##5, in##3);  \
+  \
+  tmp1l = vec_msums(in##53l, pw_mf050_mf256, z4l);  \
+  tmp1h = vec_msums(in##53h, pw_mf050_mf256, z4h);  \
+  tmp2l = vec_msums(in##53l, pw_mf256_f050, z3l);  \
+  tmp2h = vec_msums(in##53h, pw_mf256_f050, z3h);  \
+  \
+  /* Final output stage */  \
+  \
+  out0l = vec_add(tmp10l, tmp3l);  \
+  out0h = vec_add(tmp10h, tmp3h);  \
+  out7l = vec_sub(tmp10l, tmp3l);  \
+  out7h = vec_sub(tmp10h, tmp3h);  \
+  \
+  out0l = vec_sra(out0l, descale_p##PASS);  \
+  out0h = vec_sra(out0h, descale_p##PASS);  \
+  out7l = vec_sra(out7l, descale_p##PASS);  \
+  out7h = vec_sra(out7h, descale_p##PASS);  \
+  \
+  out0 = vec_pack(out0l, out0h);  \
+  out7 = vec_pack(out7l, out7h);  \
+  \
+  out1l = vec_add(tmp11l, tmp2l);  \
+  out1h = vec_add(tmp11h, tmp2h);  \
+  out6l = vec_sub(tmp11l, tmp2l);  \
+  out6h = vec_sub(tmp11h, tmp2h);  \
+  \
+  out1l = vec_sra(out1l, descale_p##PASS);  \
+  out1h = vec_sra(out1h, descale_p##PASS);  \
+  out6l = vec_sra(out6l, descale_p##PASS);  \
+  out6h = vec_sra(out6h, descale_p##PASS);  \
+  \
+  out1 = vec_pack(out1l, out1h);  \
+  out6 = vec_pack(out6l, out6h);  \
+  \
+  out2l = vec_add(tmp12l, tmp1l);  \
+  out2h = vec_add(tmp12h, tmp1h);  \
+  out5l = vec_sub(tmp12l, tmp1l);  \
+  out5h = vec_sub(tmp12h, tmp1h);  \
+  \
+  out2l = vec_sra(out2l, descale_p##PASS);  \
+  out2h = vec_sra(out2h, descale_p##PASS);  \
+  out5l = vec_sra(out5l, descale_p##PASS);  \
+  out5h = vec_sra(out5h, descale_p##PASS);  \
+  \
+  out2 = vec_pack(out2l, out2h);  \
+  out5 = vec_pack(out5l, out5h);  \
+  \
+  out3l = vec_add(tmp13l, tmp0l);  \
+  out3h = vec_add(tmp13h, tmp0h);  \
+  out4l = vec_sub(tmp13l, tmp0l);  \
+  out4h = vec_sub(tmp13h, tmp0h);  \
+  \
+  out3l = vec_sra(out3l, descale_p##PASS);  \
+  out3h = vec_sra(out3h, descale_p##PASS);  \
+  out4l = vec_sra(out4l, descale_p##PASS);  \
+  out4h = vec_sra(out4h, descale_p##PASS);  \
+  \
+  out3 = vec_pack(out3l, out3h);  \
+  out4 = vec_pack(out4l, out4h);  \
+}
+
+
+void
+jsimd_idct_islow_altivec (void * dct_table_, JCOEFPTR coef_block,
+                          JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+  short *dct_table = (short *)dct_table_;
+  int *outptr;
+
+  __vector short row0, row1, row2, row3, row4, row5, row6, row7,
+    col0, col1, col2, col3, col4, col5, col6, col7,
+    quant0, quant1, quant2, quant3, quant4, quant5, quant6, quant7,
+    tmp0, tmp1, tmp2, tmp3, z3, z4,
+    z34l, z34h, col71l, col71h, col26l, col26h, col53l, col53h,
+    row71l, row71h, row26l, row26h, row53l, row53h,
+    out0, out1, out2, out3, out4, out5, out6, out7;
+  __vector int tmp0l, tmp0h, tmp1l, tmp1h, tmp2l, tmp2h, tmp3l, tmp3h,
+    tmp10l, tmp10h, tmp11l, tmp11h, tmp12l, tmp12h, tmp13l, tmp13h,
+    z3l, z3h, z4l, z4h,
+    out0l, out0h, out1l, out1h, out2l, out2h, out3l, out3h, out4l, out4h,
+    out5l, out5h, out6l, out6h, out7l, out7h;
+  __vector signed char outb;
+
+  /* Constants */
+  __vector short pw_zero = { __8X(0) },
+    pw_f130_f054 = { __4X2(F_0_541 + F_0_765, F_0_541) },
+    pw_f054_mf130 = { __4X2(F_0_541, F_0_541 - F_1_847) },
+    pw_mf078_f117 = { __4X2(F_1_175 - F_1_961, F_1_175) },
+    pw_f117_f078 = { __4X2(F_1_175, F_1_175 - F_0_390) },
+    pw_mf060_mf089 = { __4X2(F_0_298 - F_0_899, -F_0_899) },
+    pw_mf089_f060 = { __4X2(-F_0_899, F_1_501 - F_0_899) },
+    pw_mf050_mf256 = { __4X2(F_2_053 - F_2_562, -F_2_562) },
+    pw_mf256_f050 = { __4X2(-F_2_562, F_3_072 - F_2_562) };
+  __vector unsigned short pass1_bits = { __8X(PASS1_BITS) };
+  __vector int pd_zero = { __4X(0) },
+    pd_descale_p1 = { __4X(1 << (DESCALE_P1 - 1)) },
+    pd_descale_p2 = { __4X(1 << (DESCALE_P2 - 1)) };
+  __vector unsigned int descale_p1 = { __4X(DESCALE_P1) },
+    descale_p2 = { __4X(DESCALE_P2) },
+    const_bits = { __4X(CONST_BITS) };
+  __vector signed char pb_centerjsamp = { __16X(CENTERJSAMPLE) };
+
+  /* Pass 1: process columns */
+
+  col0 = vec_ld(0, coef_block);
+  col1 = vec_ld(16, coef_block);
+  col2 = vec_ld(32, coef_block);
+  col3 = vec_ld(48, coef_block);
+  col4 = vec_ld(64, coef_block);
+  col5 = vec_ld(80, coef_block);
+  col6 = vec_ld(96, coef_block);
+  col7 = vec_ld(112, coef_block);
+
+  tmp1 = vec_or(col1, col2);
+  tmp2 = vec_or(col3, col4);
+  tmp1 = vec_or(tmp1, tmp2);
+  tmp3 = vec_or(col5, col6);
+  tmp3 = vec_or(tmp3, col7);
+  tmp1 = vec_or(tmp1, tmp3);
+
+  quant0 = vec_ld(0, dct_table);
+  col0 = vec_mladd(col0, quant0, pw_zero);
+
+  if (vec_all_eq(tmp1, pw_zero)) {
+    /* AC terms all zero */
+
+    col0 = vec_sl(col0, pass1_bits);
+
+    row0 = vec_splat(col0, 0);
+    row1 = vec_splat(col0, 1);
+    row2 = vec_splat(col0, 2);
+    row3 = vec_splat(col0, 3);
+    row4 = vec_splat(col0, 4);
+    row5 = vec_splat(col0, 5);
+    row6 = vec_splat(col0, 6);
+    row7 = vec_splat(col0, 7);
+
+  } else {
+
+    quant1 = vec_ld(16, dct_table);
+    quant2 = vec_ld(32, dct_table);
+    quant3 = vec_ld(48, dct_table);
+    quant4 = vec_ld(64, dct_table);
+    quant5 = vec_ld(80, dct_table);
+    quant6 = vec_ld(96, dct_table);
+    quant7 = vec_ld(112, dct_table);
+
+    col1 = vec_mladd(col1, quant1, pw_zero);
+    col2 = vec_mladd(col2, quant2, pw_zero);
+    col3 = vec_mladd(col3, quant3, pw_zero);
+    col4 = vec_mladd(col4, quant4, pw_zero);
+    col5 = vec_mladd(col5, quant5, pw_zero);
+    col6 = vec_mladd(col6, quant6, pw_zero);
+    col7 = vec_mladd(col7, quant7, pw_zero);
+
+    DO_IDCT(col, 1);
+
+    TRANSPOSE(out, row);
+  }
+
+  /* Pass 2: process rows */
+
+  DO_IDCT(row, 2);
+
+  TRANSPOSE(out, col);
+
+  outb = vec_packs(col0, col0);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[0] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col1, col1);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[1] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col2, col2);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[2] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col3, col3);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[3] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col4, col4);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[4] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col5, col5);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[5] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col6, col6);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[6] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+
+  outb = vec_packs(col7, col7);
+  outb = vec_add(outb, pb_centerjsamp);
+  outptr = (int *)(output_buf[7] + output_col);
+  vec_ste((__vector int)outb, 0, outptr);
+  vec_ste((__vector int)outb, 4, outptr);
+}
diff --git a/simd/jquanti-altivec.c b/simd/jquanti-altivec.c
new file mode 100644
index 0000000..2fbec2d
--- /dev/null
+++ b/simd/jquanti-altivec.c
@@ -0,0 +1,252 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, 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
+ * 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.
+ */
+
+/* INTEGER QUANTIZATION AND SAMPLE CONVERSION */
+
+#include "jsimd_altivec.h"
+
+
+/* NOTE: The address will either be aligned or offset by 8 bytes, so we can
+ * always get the data we want by using a single vector load (although we may
+ * have to permute the result.)
+ */
+#if __BIG_ENDIAN__
+
+#define LOAD_ROW(row) {  \
+  elemptr = sample_data[row] + start_col;  \
+  in##row = vec_ld(0, elemptr);  \
+  if ((size_t)elemptr & 15)  \
+    in##row = vec_perm(in##row, in##row, vec_lvsl(0, elemptr));  \
+}
+
+#else
+
+#define LOAD_ROW(row) {  \
+  elemptr = sample_data[row] + start_col;  \
+  in##row = vec_vsx_ld(0, elemptr);  \
+}
+
+#endif
+
+
+void
+jsimd_convsamp_altivec (JSAMPARRAY sample_data, JDIMENSION start_col,
+                        DCTELEM * workspace)
+{
+  JSAMPROW elemptr;
+
+  __vector unsigned char in0, in1, in2, in3, in4, in5, in6, in7;
+  __vector short out0, out1, out2, out3, out4, out5, out6, out7;
+
+  /* Constants */
+  __vector short pw_centerjsamp = { __8X(CENTERJSAMPLE) };
+  __vector unsigned char pb_zero = { __16X(0) };
+
+  LOAD_ROW(0);
+  LOAD_ROW(1);
+  LOAD_ROW(2);
+  LOAD_ROW(3);
+  LOAD_ROW(4);
+  LOAD_ROW(5);
+  LOAD_ROW(6);
+  LOAD_ROW(7);
+
+  out0 = (__vector short)VEC_UNPACKHU(in0);
+  out1 = (__vector short)VEC_UNPACKHU(in1);
+  out2 = (__vector short)VEC_UNPACKHU(in2);
+  out3 = (__vector short)VEC_UNPACKHU(in3);
+  out4 = (__vector short)VEC_UNPACKHU(in4);
+  out5 = (__vector short)VEC_UNPACKHU(in5);
+  out6 = (__vector short)VEC_UNPACKHU(in6);
+  out7 = (__vector short)VEC_UNPACKHU(in7);
+
+  out0 = vec_sub(out0, pw_centerjsamp);
+  out1 = vec_sub(out1, pw_centerjsamp);
+  out2 = vec_sub(out2, pw_centerjsamp);
+  out3 = vec_sub(out3, pw_centerjsamp);
+  out4 = vec_sub(out4, pw_centerjsamp);
+  out5 = vec_sub(out5, pw_centerjsamp);
+  out6 = vec_sub(out6, pw_centerjsamp);
+  out7 = vec_sub(out7, pw_centerjsamp);
+
+  vec_st(out0, 0, workspace);
+  vec_st(out1, 16, workspace);
+  vec_st(out2, 32, workspace);
+  vec_st(out3, 48, workspace);
+  vec_st(out4, 64, workspace);
+  vec_st(out5, 80, workspace);
+  vec_st(out6, 96, workspace);
+  vec_st(out7, 112, workspace);
+}
+
+
+#define WORD_BIT 16
+
+/* There is no AltiVec 16-bit unsigned multiply instruction, hence this.
+   We basically need an unsigned equivalent of vec_madds(). */
+
+#define MULTIPLY(vs0, vs1, out) {  \
+  tmpe = vec_mule((__vector unsigned short)vs0,  \
+                  (__vector unsigned short)vs1);  \
+  tmpo = vec_mulo((__vector unsigned short)vs0,  \
+                  (__vector unsigned short)vs1);  \
+  out = (__vector short)vec_perm((__vector unsigned short)tmpe,  \
+                                 (__vector unsigned short)tmpo,  \
+                                 shift_pack_index);  \
+}
+
+void
+jsimd_quantize_altivec (JCOEFPTR coef_block, DCTELEM * divisors,
+                        DCTELEM * workspace)
+{
+  __vector short row0, row1, row2, row3, row4, row5, row6, row7,
+    row0s, row1s, row2s, row3s, row4s, row5s, row6s, row7s,
+    corr0, corr1, corr2, corr3, corr4, corr5, corr6, corr7,
+    recip0, recip1, recip2, recip3, recip4, recip5, recip6, recip7,
+    scale0, scale1, scale2, scale3, scale4, scale5, scale6, scale7;
+  __vector unsigned int tmpe, tmpo;
+
+  /* Constants */
+  __vector unsigned short pw_word_bit_m1 = { __8X(WORD_BIT - 1) };
+#if __BIG_ENDIAN__
+  __vector unsigned char shift_pack_index =
+    {0,1,16,17,4,5,20,21,8,9,24,25,12,13,28,29};
+#else
+  __vector unsigned char shift_pack_index =
+    {2,3,18,19,6,7,22,23,10,11,26,27,14,15,30,31};
+#endif
+
+  row0 = vec_ld(0, workspace);
+  row1 = vec_ld(16, workspace);
+  row2 = vec_ld(32, workspace);
+  row3 = vec_ld(48, workspace);
+  row4 = vec_ld(64, workspace);
+  row5 = vec_ld(80, workspace);
+  row6 = vec_ld(96, workspace);
+  row7 = vec_ld(112, workspace);
+
+  /* Branch-less absolute value */
+  row0s = vec_sra(row0, pw_word_bit_m1);
+  row1s = vec_sra(row1, pw_word_bit_m1);
+  row2s = vec_sra(row2, pw_word_bit_m1);
+  row3s = vec_sra(row3, pw_word_bit_m1);
+  row4s = vec_sra(row4, pw_word_bit_m1);
+  row5s = vec_sra(row5, pw_word_bit_m1);
+  row6s = vec_sra(row6, pw_word_bit_m1);
+  row7s = vec_sra(row7, pw_word_bit_m1);
+  row0 = vec_xor(row0, row0s);
+  row1 = vec_xor(row1, row1s);
+  row2 = vec_xor(row2, row2s);
+  row3 = vec_xor(row3, row3s);
+  row4 = vec_xor(row4, row4s);
+  row5 = vec_xor(row5, row5s);
+  row6 = vec_xor(row6, row6s);
+  row7 = vec_xor(row7, row7s);
+  row0 = vec_sub(row0, row0s);
+  row1 = vec_sub(row1, row1s);
+  row2 = vec_sub(row2, row2s);
+  row3 = vec_sub(row3, row3s);
+  row4 = vec_sub(row4, row4s);
+  row5 = vec_sub(row5, row5s);
+  row6 = vec_sub(row6, row6s);
+  row7 = vec_sub(row7, row7s);
+
+  corr0 = vec_ld(DCTSIZE2 * 2, divisors);
+  corr1 = vec_ld(DCTSIZE2 * 2 + 16, divisors);
+  corr2 = vec_ld(DCTSIZE2 * 2 + 32, divisors);
+  corr3 = vec_ld(DCTSIZE2 * 2 + 48, divisors);
+  corr4 = vec_ld(DCTSIZE2 * 2 + 64, divisors);
+  corr5 = vec_ld(DCTSIZE2 * 2 + 80, divisors);
+  corr6 = vec_ld(DCTSIZE2 * 2 + 96, divisors);
+  corr7 = vec_ld(DCTSIZE2 * 2 + 112, divisors);
+
+  row0 = vec_add(row0, corr0);
+  row1 = vec_add(row1, corr1);
+  row2 = vec_add(row2, corr2);
+  row3 = vec_add(row3, corr3);
+  row4 = vec_add(row4, corr4);
+  row5 = vec_add(row5, corr5);
+  row6 = vec_add(row6, corr6);
+  row7 = vec_add(row7, corr7);
+
+  recip0 = vec_ld(0, divisors);
+  recip1 = vec_ld(16, divisors);
+  recip2 = vec_ld(32, divisors);
+  recip3 = vec_ld(48, divisors);
+  recip4 = vec_ld(64, divisors);
+  recip5 = vec_ld(80, divisors);
+  recip6 = vec_ld(96, divisors);
+  recip7 = vec_ld(112, divisors);
+
+  MULTIPLY(row0, recip0, row0);
+  MULTIPLY(row1, recip1, row1);
+  MULTIPLY(row2, recip2, row2);
+  MULTIPLY(row3, recip3, row3);
+  MULTIPLY(row4, recip4, row4);
+  MULTIPLY(row5, recip5, row5);
+  MULTIPLY(row6, recip6, row6);
+  MULTIPLY(row7, recip7, row7);
+
+  scale0 = vec_ld(DCTSIZE2 * 4, divisors);
+  scale1 = vec_ld(DCTSIZE2 * 4 + 16, divisors);
+  scale2 = vec_ld(DCTSIZE2 * 4 + 32, divisors);
+  scale3 = vec_ld(DCTSIZE2 * 4 + 48, divisors);
+  scale4 = vec_ld(DCTSIZE2 * 4 + 64, divisors);
+  scale5 = vec_ld(DCTSIZE2 * 4 + 80, divisors);
+  scale6 = vec_ld(DCTSIZE2 * 4 + 96, divisors);
+  scale7 = vec_ld(DCTSIZE2 * 4 + 112, divisors);
+
+  MULTIPLY(row0, scale0, row0);
+  MULTIPLY(row1, scale1, row1);
+  MULTIPLY(row2, scale2, row2);
+  MULTIPLY(row3, scale3, row3);
+  MULTIPLY(row4, scale4, row4);
+  MULTIPLY(row5, scale5, row5);
+  MULTIPLY(row6, scale6, row6);
+  MULTIPLY(row7, scale7, row7);
+
+  row0 = vec_xor(row0, row0s);
+  row1 = vec_xor(row1, row1s);
+  row2 = vec_xor(row2, row2s);
+  row3 = vec_xor(row3, row3s);
+  row4 = vec_xor(row4, row4s);
+  row5 = vec_xor(row5, row5s);
+  row6 = vec_xor(row6, row6s);
+  row7 = vec_xor(row7, row7s);
+  row0 = vec_sub(row0, row0s);
+  row1 = vec_sub(row1, row1s);
+  row2 = vec_sub(row2, row2s);
+  row3 = vec_sub(row3, row3s);
+  row4 = vec_sub(row4, row4s);
+  row5 = vec_sub(row5, row5s);
+  row6 = vec_sub(row6, row6s);
+  row7 = vec_sub(row7, row7s);
+
+  vec_st(row0, 0, coef_block);
+  vec_st(row1, 16, coef_block);
+  vec_st(row2, 32, coef_block);
+  vec_st(row3, 48, coef_block);
+  vec_st(row4, 64, coef_block);
+  vec_st(row5, 80, coef_block);
+  vec_st(row6, 96, coef_block);
+  vec_st(row7, 112, coef_block);
+}
diff --git a/simd/jsimd.h b/simd/jsimd.h
index c5abd45..c0de7e7 100644
--- a/simd/jsimd.h
+++ b/simd/jsimd.h
@@ -2,7 +2,7 @@
  * simd/jsimd.h
  *
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright 2011 D. R. Commander
+ * Copyright (C) 2011, 2014-2015 D. R. Commander
  * Copyright (C) 2013-2014, MIPS Technologies, Inc., California
  * Copyright (C) 2014 Linaro Limited
  *
@@ -21,6 +21,7 @@
 #define JSIMD_SSE2       0x08
 #define JSIMD_ARM_NEON   0x10
 #define JSIMD_MIPS_DSPR2 0x20
+#define JSIMD_ALTIVEC    0x40
 
 /* SIMD Ext: retrieve SIMD/CPU information */
 EXTERN(unsigned int) jpeg_simd_cpu_support (void);
@@ -115,6 +116,28 @@
         (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
          JDIMENSION output_row, int num_rows);
 
+EXTERN(void) jsimd_rgb_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extrgb_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extrgbx_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extbgr_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extbgrx_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extxbgr_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extxrgb_ycc_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+
 /* RGB & extended RGB --> Grayscale Colorspace Conversion */
 EXTERN(void) jsimd_rgb_gray_convert_mmx
         (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
@@ -183,6 +206,28 @@
         (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
          JDIMENSION output_row, int num_rows);
 
+EXTERN(void) jsimd_rgb_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extrgb_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extrgbx_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extbgr_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extbgrx_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extxbgr_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+EXTERN(void) jsimd_extxrgb_gray_convert_altivec
+        (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+         JDIMENSION output_row, int num_rows);
+
 /* YCC --> RGB & extended RGB Colorspace Conversion */
 EXTERN(void) jsimd_ycc_rgb_convert_mmx
         (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
@@ -276,6 +321,28 @@
         (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
          JSAMPARRAY output_buf, int num_rows);
 
+EXTERN(void) jsimd_ycc_rgb_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extrgb_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extrgbx_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extbgr_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extbgrx_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extxbgr_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+EXTERN(void) jsimd_ycc_extxrgb_convert_altivec
+        (JDIMENSION out_width, JSAMPIMAGE input_buf, JDIMENSION input_row,
+         JSAMPARRAY output_buf, int num_rows);
+
 /* NULL Colorspace Conversion */
 EXTERN(void) jsimd_c_null_convert_mips_dspr2
         (JDIMENSION img_width, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
@@ -297,6 +364,11 @@
          JDIMENSION v_samp_factor, JDIMENSION width_blocks,
          JSAMPARRAY input_data, JSAMPARRAY output_data);
 
+EXTERN(void) jsimd_h2v1_downsample_altivec
+        (JDIMENSION image_width, int max_v_samp_factor,
+         JDIMENSION v_samp_factor, JDIMENSION width_blocks,
+         JSAMPARRAY input_data, JSAMPARRAY output_data);
+
 /* h2v2 Downsampling */
 EXTERN(void) jsimd_h2v2_downsample_mmx
         (JDIMENSION image_width, int max_v_samp_factor,
@@ -313,6 +385,11 @@
          JDIMENSION v_samp_factor, JDIMENSION width_blocks,
          JSAMPARRAY input_data, JSAMPARRAY output_data);
 
+EXTERN(void) jsimd_h2v2_downsample_altivec
+        (JDIMENSION image_width, int max_v_samp_factor,
+         JDIMENSION v_samp_factor, JDIMENSION width_blocks,
+         JSAMPARRAY input_data, JSAMPARRAY output_data);
+
 /* h2v2 Smooth Downsampling */
 EXTERN(void) jsimd_h2v2_smooth_downsample_mips_dspr2
         (JSAMPARRAY input_data, JSAMPARRAY output_data,
@@ -348,6 +425,12 @@
          JSAMPARRAY * output_data_ptr, JDIMENSION output_width,
          int max_v_samp_factor);
 
+EXTERN(void) jsimd_h2v1_upsample_altivec
+        (int max_v_samp_factor, JDIMENSION output_width, JSAMPARRAY input_data,
+         JSAMPARRAY * output_data_ptr);
+EXTERN(void) jsimd_h2v2_upsample_altivec
+        (int max_v_samp_factor, JDIMENSION output_width, JSAMPARRAY input_data,
+         JSAMPARRAY * output_data_ptr);
 
 /* Fancy Upsampling */
 EXTERN(void) jsimd_h2v1_fancy_upsample_mmx
@@ -376,6 +459,13 @@
         (int max_v_samp_factor, JDIMENSION downsampled_width,
          JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr);
 
+EXTERN(void) jsimd_h2v1_fancy_upsample_altivec
+        (int max_v_samp_factor, JDIMENSION downsampled_width,
+         JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr);
+EXTERN(void) jsimd_h2v2_fancy_upsample_altivec
+        (int max_v_samp_factor, JDIMENSION downsampled_width,
+         JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr);
+
 /* Merged Upsampling */
 EXTERN(void) jsimd_h2v1_merged_upsample_mmx
         (JDIMENSION output_width, JSAMPIMAGE input_buf,
@@ -510,6 +600,50 @@
         (JDIMENSION output_width, JSAMPIMAGE input_buf,
          JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf, JSAMPLE* range);
 
+EXTERN(void) jsimd_h2v1_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extrgb_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extrgbx_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extbgr_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extbgrx_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extxbgr_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v1_extxrgb_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+
+EXTERN(void) jsimd_h2v2_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extrgb_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extrgbx_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extbgr_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extbgrx_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extxbgr_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+EXTERN(void) jsimd_h2v2_extxrgb_merged_upsample_altivec
+        (JDIMENSION output_width, JSAMPIMAGE input_buf,
+         JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+
 /* Sample Conversion */
 EXTERN(void) jsimd_convsamp_mmx
         (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace);
@@ -523,6 +657,9 @@
 EXTERN(void) jsimd_convsamp_mips_dspr2
         (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace);
 
+EXTERN(void) jsimd_convsamp_altivec
+        (JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM * workspace);
+
 /* Floating Point Sample Conversion */
 EXTERN(void) jsimd_convsamp_float_3dnow
         (JSAMPARRAY sample_data, JDIMENSION start_col, FAST_FLOAT * workspace);
@@ -544,6 +681,8 @@
 
 EXTERN(void) jsimd_fdct_islow_mips_dspr2 (DCTELEM * data);
 
+EXTERN(void) jsimd_fdct_islow_altivec (DCTELEM * data);
+
 /* Fast Integer Forward DCT */
 EXTERN(void) jsimd_fdct_ifast_mmx (DCTELEM * data);
 
@@ -554,6 +693,8 @@
 
 EXTERN(void) jsimd_fdct_ifast_mips_dspr2 (DCTELEM * data);
 
+EXTERN(void) jsimd_fdct_ifast_altivec (DCTELEM * data);
+
 /* Floating Point Forward DCT */
 EXTERN(void) jsimd_fdct_float_3dnow (FAST_FLOAT * data);
 
@@ -573,6 +714,9 @@
 EXTERN(void) jsimd_quantize_mips_dspr2
         (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace);
 
+EXTERN(void) jsimd_quantize_altivec
+        (JCOEFPTR coef_block, DCTELEM * divisors, DCTELEM * workspace);
+
 /* Floating Point Quantization */
 EXTERN(void) jsimd_quantize_float_3dnow
         (JCOEFPTR coef_block, FAST_FLOAT * divisors, FAST_FLOAT * workspace);
@@ -641,6 +785,10 @@
         (void * dct_table, JCOEFPTR coef_block, int * output_buf,
          JSAMPLE * output_col);
 
+EXTERN(void) jsimd_idct_islow_altivec
+        (void * dct_table, JCOEFPTR coef_block, JSAMPARRAY output_buf,
+         JDIMENSION output_col);
+
 /* Fast Integer Inverse DCT */
 EXTERN(void) jsimd_idct_ifast_mmx
         (void * dct_table, JCOEFPTR coef_block, JSAMPARRAY output_buf,
@@ -662,6 +810,10 @@
         (DCTELEM * wsptr, JSAMPARRAY output_buf, JDIMENSION output_col,
          const int * idct_coefs);
 
+EXTERN(void) jsimd_idct_ifast_altivec
+        (void * dct_table, JCOEFPTR coef_block, JSAMPARRAY output_buf,
+         JDIMENSION output_col);
+
 /* Floating Point Inverse DCT */
 EXTERN(void) jsimd_idct_float_3dnow
         (void * dct_table, JCOEFPTR coef_block, JSAMPARRAY output_buf,
diff --git a/simd/jsimd_altivec.h b/simd/jsimd_altivec.h
new file mode 100644
index 0000000..2660219
--- /dev/null
+++ b/simd/jsimd_altivec.h
@@ -0,0 +1,99 @@
+/*
+ * AltiVec optimizations for libjpeg-turbo
+ *
+ * Copyright (C) 2014-2015, 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
+ * 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.
+ */
+
+#define JPEG_INTERNALS
+#include "../jinclude.h"
+#include "../jpeglib.h"
+#include "../jsimd.h"
+#include "../jdct.h"
+#include "../jsimddct.h"
+#include "jsimd.h"
+#include <altivec.h>
+
+
+/* Common code */
+
+#define __4X(a) a, a, a, a
+#define __4X2(a, b) a, b, a, b, a, b, a, b
+#define __8X(a) __4X(a), __4X(a)
+#define __16X(a) __8X(a), __8X(a)
+
+#define TRANSPOSE(row, col)  \
+{  \
+  __vector short row04l, row04h, row15l, row15h,  \
+                 row26l, row26h, row37l, row37h;  \
+  __vector short col01e, col01o, col23e, col23o,  \
+                 col45e, col45o, col67e, col67o;  \
+  \
+                                       /* transpose coefficients (phase 1) */ \
+  row04l = vec_mergeh(row##0, row##4); /* row04l=(00 40 01 41 02 42 03 43) */ \
+  row04h = vec_mergel(row##0, row##4); /* row04h=(04 44 05 45 06 46 07 47) */ \
+  row15l = vec_mergeh(row##1, row##5); /* row15l=(10 50 11 51 12 52 13 53) */ \
+  row15h = vec_mergel(row##1, row##5); /* row15h=(14 54 15 55 16 56 17 57) */ \
+  row26l = vec_mergeh(row##2, row##6); /* row26l=(20 60 21 61 22 62 23 63) */ \
+  row26h = vec_mergel(row##2, row##6); /* row26h=(24 64 25 65 26 66 27 67) */ \
+  row37l = vec_mergeh(row##3, row##7); /* row37l=(30 70 31 71 32 72 33 73) */ \
+  row37h = vec_mergel(row##3, row##7); /* row37h=(34 74 35 75 36 76 37 77) */ \
+  \
+                                       /* transpose coefficients (phase 2) */ \
+  col01e = vec_mergeh(row04l, row26l); /* col01e=(00 20 40 60 01 21 41 61) */ \
+  col23e = vec_mergel(row04l, row26l); /* col23e=(02 22 42 62 03 23 43 63) */ \
+  col45e = vec_mergeh(row04h, row26h); /* col45e=(04 24 44 64 05 25 45 65) */ \
+  col67e = vec_mergel(row04h, row26h); /* col67e=(06 26 46 66 07 27 47 67) */ \
+  col01o = vec_mergeh(row15l, row37l); /* col01o=(10 30 50 70 11 31 51 71) */ \
+  col23o = vec_mergel(row15l, row37l); /* col23o=(12 32 52 72 13 33 53 73) */ \
+  col45o = vec_mergeh(row15h, row37h); /* col45o=(14 34 54 74 15 35 55 75) */ \
+  col67o = vec_mergel(row15h, row37h); /* col67o=(16 36 56 76 17 37 57 77) */ \
+  \
+                                       /* transpose coefficients (phase 3) */ \
+  col##0 = vec_mergeh(col01e, col01o); /* col0=(00 10 20 30 40 50 60 70) */   \
+  col##1 = vec_mergel(col01e, col01o); /* col1=(01 11 21 31 41 51 61 71) */   \
+  col##2 = vec_mergeh(col23e, col23o); /* col2=(02 12 22 32 42 52 62 72) */   \
+  col##3 = vec_mergel(col23e, col23o); /* col3=(03 13 23 33 43 53 63 73) */   \
+  col##4 = vec_mergeh(col45e, col45o); /* col4=(04 14 24 34 44 54 64 74) */   \
+  col##5 = vec_mergel(col45e, col45o); /* col5=(05 15 25 35 45 55 65 75) */   \
+  col##6 = vec_mergeh(col67e, col67o); /* col6=(06 16 26 36 46 56 66 76) */   \
+  col##7 = vec_mergel(col67e, col67o); /* col7=(07 17 27 37 47 57 67 77) */   \
+}
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+
+/* Macros to abstract big/little endian bit twiddling */
+
+#if __BIG_ENDIAN__
+
+#define VEC_LD(a, b) vec_ld(a, b)
+#define VEC_ST(a, b, c) vec_st(a, b, c)
+#define VEC_UNPACKHU(a) vec_mergeh(pb_zero, a)
+#define VEC_UNPACKLU(a) vec_mergel(pb_zero, a)
+
+#else
+
+#define VEC_LD(a, b) vec_vsx_ld(a, b)
+#define VEC_ST(a, b, c) vec_vsx_st(a, b, c)
+#define VEC_UNPACKHU(a) vec_mergeh(a, pb_zero)
+#define VEC_UNPACKLU(a) vec_mergel(a, pb_zero)
+
+#endif
diff --git a/simd/jsimd_mips_dspr2.S b/simd/jsimd_mips_dspr2.S
index 65c169a..bd55c76 100644
--- a/simd/jsimd_mips_dspr2.S
+++ b/simd/jsimd_mips_dspr2.S
@@ -2841,54 +2841,54 @@
     mtc1       t1, f0
     li         t0, 63
 0:
-    lwc1       f1, 0(a2)
-    lwc1       f5, 0(a1)
-    lwc1       f2, 4(a2)
-    lwc1       f6, 4(a1)
-    lwc1       f3, 8(a2)
-    lwc1       f7, 8(a1)
-    lwc1       f4, 12(a2)
-    lwc1       f8, 12(a1)
-    madd.s     f1, f0, f1, f5
-    madd.s     f2, f0, f2, f6
-    madd.s     f3, f0, f3, f7
-    madd.s     f4, f0, f4, f8
-    lwc1       f5, 16(a1)
-    lwc1       f6, 20(a1)
-    trunc.w.s  f1, f1
+    lwc1       f2, 0(a2)
+    lwc1       f10, 0(a1)
+    lwc1       f4, 4(a2)
+    lwc1       f12, 4(a1)
+    lwc1       f6, 8(a2)
+    lwc1       f14, 8(a1)
+    lwc1       f8, 12(a2)
+    lwc1       f16, 12(a1)
+    madd.s     f2, f0, f2, f10
+    madd.s     f4, f0, f4, f12
+    madd.s     f6, f0, f6, f14
+    madd.s     f8, f0, f8, f16
+    lwc1       f10, 16(a1)
+    lwc1       f12, 20(a1)
     trunc.w.s  f2, f2
-    trunc.w.s  f3, f3
     trunc.w.s  f4, f4
-    lwc1       f7, 24(a1)
-    lwc1       f8, 28(a1)
-    mfc1       t1, f1
-    mfc1       t2, f2
-    mfc1       t3, f3
-    mfc1       t4, f4
-    lwc1       f1, 16(a2)
-    lwc1       f2, 20(a2)
-    lwc1       f3, 24(a2)
-    lwc1       f4, 28(a2)
-    madd.s     f1, f0, f1, f5
-    madd.s     f2, f0, f2, f6
-    madd.s     f3, f0, f3, f7
-    madd.s     f4, f0, f4, f8
+    trunc.w.s  f6, f6
+    trunc.w.s  f8, f8
+    lwc1       f14, 24(a1)
+    lwc1       f16, 28(a1)
+    mfc1       t1, f2
+    mfc1       t2, f4
+    mfc1       t3, f6
+    mfc1       t4, f8
+    lwc1       f2, 16(a2)
+    lwc1       f4, 20(a2)
+    lwc1       f6, 24(a2)
+    lwc1       f8, 28(a2)
+    madd.s     f2, f0, f2, f10
+    madd.s     f4, f0, f4, f12
+    madd.s     f6, f0, f6, f14
+    madd.s     f8, f0, f8, f16
     addiu      t1, t1, -16384
     addiu      t2, t2, -16384
     addiu      t3, t3, -16384
     addiu      t4, t4, -16384
-    trunc.w.s  f1, f1
     trunc.w.s  f2, f2
-    trunc.w.s  f3, f3
     trunc.w.s  f4, f4
+    trunc.w.s  f6, f6
+    trunc.w.s  f8, f8
     sh         t1, 0(a0)
     sh         t2, 2(a0)
     sh         t3, 4(a0)
     sh         t4, 6(a0)
-    mfc1       t1, f1
-    mfc1       t2, f2
-    mfc1       t3, f3
-    mfc1       t4, f4
+    mfc1       t1, f2
+    mfc1       t2, f4
+    mfc1       t3, f6
+    mfc1       t4, f8
     addiu      t0, t0, -8
     addiu      a2, a2, 32
     addiu      a1, a1, 32
@@ -4151,32 +4151,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 4(a0)
-    swc1     f1, 0(a2)
-    swc1     f2, 4(a2)
-    swc1     f3, 8(a2)
+    swc1     f2, 0(a2)
+    swc1     f4, 4(a2)
+    swc1     f6, 8(a2)
     addu     t0, t0, a1
-    swc1     f4, 12(a2)
-    swc1     f5, 16(a2)
-    swc1     f6, 20(a2)
-    swc1     f7, 24(a2)
-    swc1     f8, 28(a2)
+    swc1     f8, 12(a2)
+    swc1     f10, 16(a2)
+    swc1     f12, 20(a2)
+    swc1     f14, 24(a2)
+    swc1     f16, 28(a2)
     //elemr 1
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4194,32 +4194,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 8(a0)
-    swc1     f1, 32(a2)
-    swc1     f2, 36(a2)
-    swc1     f3, 40(a2)
+    swc1     f2, 32(a2)
+    swc1     f4, 36(a2)
+    swc1     f6, 40(a2)
     addu     t0, t0, a1
-    swc1     f4, 44(a2)
-    swc1     f5, 48(a2)
-    swc1     f6, 52(a2)
-    swc1     f7, 56(a2)
-    swc1     f8, 60(a2)
+    swc1     f8, 44(a2)
+    swc1     f10, 48(a2)
+    swc1     f12, 52(a2)
+    swc1     f14, 56(a2)
+    swc1     f16, 60(a2)
     //elemr 2
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4237,32 +4237,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 12(a0)
-    swc1     f1, 64(a2)
-    swc1     f2, 68(a2)
-    swc1     f3, 72(a2)
+    swc1     f2, 64(a2)
+    swc1     f4, 68(a2)
+    swc1     f6, 72(a2)
     addu     t0, t0, a1
-    swc1     f4, 76(a2)
-    swc1     f5, 80(a2)
-    swc1     f6, 84(a2)
-    swc1     f7, 88(a2)
-    swc1     f8, 92(a2)
+    swc1     f8, 76(a2)
+    swc1     f10, 80(a2)
+    swc1     f12, 84(a2)
+    swc1     f14, 88(a2)
+    swc1     f16, 92(a2)
     //elemr 3
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4280,32 +4280,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 16(a0)
-    swc1     f1, 96(a2)
-    swc1     f2, 100(a2)
-    swc1     f3, 104(a2)
+    swc1     f2, 96(a2)
+    swc1     f4, 100(a2)
+    swc1     f6, 104(a2)
     addu     t0, t0, a1
-    swc1     f4, 108(a2)
-    swc1     f5, 112(a2)
-    swc1     f6, 116(a2)
-    swc1     f7, 120(a2)
-    swc1     f8, 124(a2)
+    swc1     f8, 108(a2)
+    swc1     f10, 112(a2)
+    swc1     f12, 116(a2)
+    swc1     f14, 120(a2)
+    swc1     f16, 124(a2)
     //elemr 4
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4323,32 +4323,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 20(a0)
-    swc1     f1, 128(a2)
-    swc1     f2, 132(a2)
-    swc1     f3, 136(a2)
+    swc1     f2, 128(a2)
+    swc1     f4, 132(a2)
+    swc1     f6, 136(a2)
     addu     t0, t0, a1
-    swc1     f4, 140(a2)
-    swc1     f5, 144(a2)
-    swc1     f6, 148(a2)
-    swc1     f7, 152(a2)
-    swc1     f8, 156(a2)
+    swc1     f8, 140(a2)
+    swc1     f10, 144(a2)
+    swc1     f12, 148(a2)
+    swc1     f14, 152(a2)
+    swc1     f16, 156(a2)
     //elemr 5
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4366,32 +4366,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 24(a0)
-    swc1     f1, 160(a2)
-    swc1     f2, 164(a2)
-    swc1     f3, 168(a2)
+    swc1     f2, 160(a2)
+    swc1     f4, 164(a2)
+    swc1     f6, 168(a2)
     addu     t0, t0, a1
-    swc1     f4, 172(a2)
-    swc1     f5, 176(a2)
-    swc1     f6, 180(a2)
-    swc1     f7, 184(a2)
-    swc1     f8, 188(a2)
+    swc1     f8, 172(a2)
+    swc1     f10, 176(a2)
+    swc1     f12, 180(a2)
+    swc1     f14, 184(a2)
+    swc1     f16, 188(a2)
     //elemr 6
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4409,32 +4409,32 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
     lw       t0, 28(a0)
-    swc1     f1, 192(a2)
-    swc1     f2, 196(a2)
-    swc1     f3, 200(a2)
+    swc1     f2, 192(a2)
+    swc1     f4, 196(a2)
+    swc1     f6, 200(a2)
     addu     t0, t0, a1
-    swc1     f4, 204(a2)
-    swc1     f5, 208(a2)
-    swc1     f6, 212(a2)
-    swc1     f7, 216(a2)
-    swc1     f8, 220(a2)
+    swc1     f8, 204(a2)
+    swc1     f10, 208(a2)
+    swc1     f12, 212(a2)
+    swc1     f14, 216(a2)
+    swc1     f16, 220(a2)
     //elemr 7
     lbu      t1, 0(t0)
     lbu      t2, 1(t0)
@@ -4452,30 +4452,30 @@
     addiu    t6, t6, -128
     addiu    t7, t7, -128
     addiu    t8, t8, -128
-    mtc1     t1, f1
-    mtc1     t2, f2
-    mtc1     t3, f3
-    mtc1     t4, f4
-    mtc1     t5, f5
-    mtc1     t6, f6
-    mtc1     t7, f7
-    mtc1     t8, f8
-    cvt.s.w  f1, f1
+    mtc1     t1, f2
+    mtc1     t2, f4
+    mtc1     t3, f6
+    mtc1     t4, f8
+    mtc1     t5, f10
+    mtc1     t6, f12
+    mtc1     t7, f14
+    mtc1     t8, f16
     cvt.s.w  f2, f2
-    cvt.s.w  f3, f3
     cvt.s.w  f4, f4
-    cvt.s.w  f5, f5
     cvt.s.w  f6, f6
-    cvt.s.w  f7, f7
     cvt.s.w  f8, f8
-    swc1     f1, 224(a2)
-    swc1     f2, 228(a2)
-    swc1     f3, 232(a2)
-    swc1     f4, 236(a2)
-    swc1     f5, 240(a2)
-    swc1     f6, 244(a2)
-    swc1     f7, 248(a2)
-    swc1     f8, 252(a2)
+    cvt.s.w  f10, f10
+    cvt.s.w  f12, f12
+    cvt.s.w  f14, f14
+    cvt.s.w  f16, f16
+    swc1     f2, 224(a2)
+    swc1     f4, 228(a2)
+    swc1     f6, 232(a2)
+    swc1     f8, 236(a2)
+    swc1     f10, 240(a2)
+    swc1     f12, 244(a2)
+    swc1     f14, 248(a2)
+    swc1     f16, 252(a2)
 
     j        ra
      nop
diff --git a/simd/jsimd_powerpc.c b/simd/jsimd_powerpc.c
new file mode 100644
index 0000000..2fc6814
--- /dev/null
+++ b/simd/jsimd_powerpc.c
@@ -0,0 +1,726 @@
+/*
+ * jsimd_powerpc.c
+ *
+ * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright 2009-2011, 2014-2015 D. R. Commander
+ *
+ * Based on the x86 SIMD extension for IJG JPEG library,
+ * Copyright (C) 1999-2006, MIYASAKA Masaru.
+ * For conditions of distribution and use, see copyright notice in jsimdext.inc
+ *
+ * This file contains the interface between the "normal" portions
+ * of the library and the SIMD implementations when running on a
+ * PowerPC architecture.
+ */
+
+#define JPEG_INTERNALS
+#include "../jinclude.h"
+#include "../jpeglib.h"
+#include "../jsimd.h"
+#include "../jdct.h"
+#include "../jsimddct.h"
+#include "jsimd.h"
+
+static unsigned int simd_support = ~0;
+
+LOCAL(void)
+init_simd (void)
+{
+  char *env = NULL;
+
+  if (simd_support != ~0U)
+    return;
+
+  simd_support = JSIMD_ALTIVEC;
+
+  /* Force different settings through environment variables */
+  env = getenv("JSIMD_FORCENONE");
+  if ((env != NULL) && (strcmp(env, "1") == 0))
+    simd_support = 0;
+}
+
+GLOBAL(int)
+jsimd_can_rgb_ycc (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_rgb_gray (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_ycc_rgb (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if ((RGB_PIXELSIZE != 3) && (RGB_PIXELSIZE != 4))
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_ycc_rgb565 (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)
+{
+  void (*altivecfct)(JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+
+  switch(cinfo->in_color_space) {
+    case JCS_EXT_RGB:
+      altivecfct=jsimd_extrgb_ycc_convert_altivec;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      altivecfct=jsimd_extrgbx_ycc_convert_altivec;
+      break;
+    case JCS_EXT_BGR:
+      altivecfct=jsimd_extbgr_ycc_convert_altivec;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      altivecfct=jsimd_extbgrx_ycc_convert_altivec;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      altivecfct=jsimd_extxbgr_ycc_convert_altivec;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      altivecfct=jsimd_extxrgb_ycc_convert_altivec;
+      break;
+    default:
+      altivecfct=jsimd_rgb_ycc_convert_altivec;
+      break;
+  }
+
+  altivecfct(cinfo->image_width, input_buf, output_buf, output_row, num_rows);
+}
+
+GLOBAL(void)
+jsimd_rgb_gray_convert (j_compress_ptr cinfo,
+                        JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+                        JDIMENSION output_row, int num_rows)
+{
+  void (*altivecfct)(JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+
+  switch(cinfo->in_color_space) {
+    case JCS_EXT_RGB:
+      altivecfct=jsimd_extrgb_gray_convert_altivec;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      altivecfct=jsimd_extrgbx_gray_convert_altivec;
+      break;
+    case JCS_EXT_BGR:
+      altivecfct=jsimd_extbgr_gray_convert_altivec;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      altivecfct=jsimd_extbgrx_gray_convert_altivec;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      altivecfct=jsimd_extxbgr_gray_convert_altivec;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      altivecfct=jsimd_extxrgb_gray_convert_altivec;
+      break;
+    default:
+      altivecfct=jsimd_rgb_gray_convert_altivec;
+      break;
+  }
+
+  altivecfct(cinfo->image_width, input_buf, output_buf, output_row, num_rows);
+}
+
+GLOBAL(void)
+jsimd_ycc_rgb_convert (j_decompress_ptr cinfo,
+                       JSAMPIMAGE input_buf, JDIMENSION input_row,
+                       JSAMPARRAY output_buf, int num_rows)
+{
+  void (*altivecfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
+
+  switch(cinfo->out_color_space) {
+    case JCS_EXT_RGB:
+      altivecfct=jsimd_ycc_extrgb_convert_altivec;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      altivecfct=jsimd_ycc_extrgbx_convert_altivec;
+      break;
+    case JCS_EXT_BGR:
+      altivecfct=jsimd_ycc_extbgr_convert_altivec;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      altivecfct=jsimd_ycc_extbgrx_convert_altivec;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      altivecfct=jsimd_ycc_extxbgr_convert_altivec;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      altivecfct=jsimd_ycc_extxrgb_convert_altivec;
+      break;
+    default:
+      altivecfct=jsimd_ycc_rgb_convert_altivec;
+      break;
+  }
+
+  altivecfct(cinfo->output_width, input_buf, input_row, output_buf, 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(int)
+jsimd_can_h2v2_downsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_downsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+                       JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  jsimd_h2v2_downsample_altivec(cinfo->image_width, cinfo->max_v_samp_factor,
+                                compptr->v_samp_factor,
+                                compptr->width_in_blocks,
+                                input_data, output_data);
+}
+
+GLOBAL(void)
+jsimd_h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+                       JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+  jsimd_h2v1_downsample_altivec(cinfo->image_width, cinfo->max_v_samp_factor,
+                                compptr->v_samp_factor,
+                                compptr->width_in_blocks,
+                                input_data, output_data);
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_upsample (j_decompress_ptr cinfo,
+                     jpeg_component_info * compptr,
+                     JSAMPARRAY input_data,
+                     JSAMPARRAY * output_data_ptr)
+{
+  jsimd_h2v2_upsample_altivec(cinfo->max_v_samp_factor, cinfo->output_width,
+                              input_data, output_data_ptr);
+}
+
+GLOBAL(void)
+jsimd_h2v1_upsample (j_decompress_ptr cinfo,
+                     jpeg_component_info * compptr,
+                     JSAMPARRAY input_data,
+                     JSAMPARRAY * output_data_ptr)
+{
+  jsimd_h2v1_upsample_altivec(cinfo->max_v_samp_factor, cinfo->output_width,
+                              input_data, output_data_ptr);
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_fancy_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_fancy_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_fancy_upsample (j_decompress_ptr cinfo,
+                           jpeg_component_info * compptr,
+                           JSAMPARRAY input_data,
+                           JSAMPARRAY * output_data_ptr)
+{
+  jsimd_h2v2_fancy_upsample_altivec(cinfo->max_v_samp_factor,
+                                    compptr->downsampled_width, input_data,
+                                    output_data_ptr);
+}
+
+GLOBAL(void)
+jsimd_h2v1_fancy_upsample (j_decompress_ptr cinfo,
+                           jpeg_component_info * compptr,
+                           JSAMPARRAY input_data,
+                           JSAMPARRAY * output_data_ptr)
+{
+  jsimd_h2v1_fancy_upsample_altivec(cinfo->max_v_samp_factor,
+                                    compptr->downsampled_width, input_data,
+                                    output_data_ptr);
+}
+
+GLOBAL(int)
+jsimd_can_h2v2_merged_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_h2v1_merged_upsample (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_h2v2_merged_upsample (j_decompress_ptr cinfo,
+                            JSAMPIMAGE input_buf,
+                            JDIMENSION in_row_group_ctr,
+                            JSAMPARRAY output_buf)
+{
+  void (*altivecfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+
+  switch(cinfo->out_color_space) {
+    case JCS_EXT_RGB:
+      altivecfct=jsimd_h2v2_extrgb_merged_upsample_altivec;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      altivecfct=jsimd_h2v2_extrgbx_merged_upsample_altivec;
+      break;
+    case JCS_EXT_BGR:
+      altivecfct=jsimd_h2v2_extbgr_merged_upsample_altivec;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      altivecfct=jsimd_h2v2_extbgrx_merged_upsample_altivec;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      altivecfct=jsimd_h2v2_extxbgr_merged_upsample_altivec;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      altivecfct=jsimd_h2v2_extxrgb_merged_upsample_altivec;
+      break;
+    default:
+      altivecfct=jsimd_h2v2_merged_upsample_altivec;
+      break;
+  }
+
+  altivecfct(cinfo->output_width, input_buf, in_row_group_ctr, output_buf);
+}
+
+GLOBAL(void)
+jsimd_h2v1_merged_upsample (j_decompress_ptr cinfo,
+                            JSAMPIMAGE input_buf,
+                            JDIMENSION in_row_group_ctr,
+                            JSAMPARRAY output_buf)
+{
+  void (*altivecfct)(JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+
+  switch(cinfo->out_color_space) {
+    case JCS_EXT_RGB:
+      altivecfct=jsimd_h2v1_extrgb_merged_upsample_altivec;
+      break;
+    case JCS_EXT_RGBX:
+    case JCS_EXT_RGBA:
+      altivecfct=jsimd_h2v1_extrgbx_merged_upsample_altivec;
+      break;
+    case JCS_EXT_BGR:
+      altivecfct=jsimd_h2v1_extbgr_merged_upsample_altivec;
+      break;
+    case JCS_EXT_BGRX:
+    case JCS_EXT_BGRA:
+      altivecfct=jsimd_h2v1_extbgrx_merged_upsample_altivec;
+      break;
+    case JCS_EXT_XBGR:
+    case JCS_EXT_ABGR:
+      altivecfct=jsimd_h2v1_extxbgr_merged_upsample_altivec;
+      break;
+    case JCS_EXT_XRGB:
+    case JCS_EXT_ARGB:
+      altivecfct=jsimd_h2v1_extxrgb_merged_upsample_altivec;
+      break;
+    default:
+      altivecfct=jsimd_h2v1_merged_upsample_altivec;
+      break;
+  }
+
+  altivecfct(cinfo->output_width, input_buf, in_row_group_ctr, output_buf);
+}
+
+GLOBAL(int)
+jsimd_can_convsamp (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (BITS_IN_JSAMPLE != 8)
+    return 0;
+  if (sizeof(JDIMENSION) != 4)
+    return 0;
+  if (sizeof(DCTELEM) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_convsamp_float (void)
+{
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_convsamp (JSAMPARRAY sample_data, JDIMENSION start_col,
+                DCTELEM * workspace)
+{
+  jsimd_convsamp_altivec(sample_data, start_col, workspace);
+}
+
+GLOBAL(void)
+jsimd_convsamp_float (JSAMPARRAY sample_data, JDIMENSION start_col,
+                      FAST_FLOAT * workspace)
+{
+}
+
+GLOBAL(int)
+jsimd_can_fdct_islow (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(DCTELEM) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_fdct_ifast (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(DCTELEM) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_fdct_float (void)
+{
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_fdct_islow (DCTELEM * data)
+{
+  jsimd_fdct_islow_altivec(data);
+}
+
+GLOBAL(void)
+jsimd_fdct_ifast (DCTELEM * data)
+{
+  jsimd_fdct_ifast_altivec(data);
+}
+
+GLOBAL(void)
+jsimd_fdct_float (FAST_FLOAT * data)
+{
+}
+
+GLOBAL(int)
+jsimd_can_quantize (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+  if (sizeof(DCTELEM) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_quantize_float (void)
+{
+  return 0;
+}
+
+GLOBAL(void)
+jsimd_quantize (JCOEFPTR coef_block, DCTELEM * divisors,
+                DCTELEM * workspace)
+{
+  jsimd_quantize_altivec(coef_block, divisors, 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(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(int)
+jsimd_can_idct_islow (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  return 0;
+}
+
+GLOBAL(int)
+jsimd_can_idct_ifast (void)
+{
+  init_simd();
+
+  /* The code is optimised for these values only */
+  if (DCTSIZE != 8)
+    return 0;
+  if (sizeof(JCOEF) != 2)
+    return 0;
+
+  if (simd_support & JSIMD_ALTIVEC)
+    return 1;
+
+  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)
+{
+  jsimd_idct_islow_altivec(compptr->dct_table, coef_block, output_buf,
+                           output_col);
+}
+
+GLOBAL(void)
+jsimd_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                  JDIMENSION output_col)
+{
+  jsimd_idct_ifast_altivec(compptr->dct_table, coef_block, output_buf,
+                           output_col);
+}
+
+GLOBAL(void)
+jsimd_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+                  JCOEFPTR coef_block, JSAMPARRAY output_buf,
+                  JDIMENSION output_col)
+{
+}
diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c
index 1bf478f..4d9900c 100644
--- a/turbojpeg-jni.c
+++ b/turbojpeg-jni.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011-2014 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2015 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:
@@ -39,23 +39,27 @@
 
 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
 
-#define _throw(msg) {  \
-	jclass _exccls=(*env)->FindClass(env, "java/lang/Exception");  \
-	if(!_exccls) goto bailout;  \
+#define _throw(msg, exceptionClass) {  \
+	jclass _exccls=(*env)->FindClass(env, exceptionClass);  \
+	if(!_exccls || (*env)->ExceptionCheck(env)) goto bailout;  \
 	(*env)->ThrowNew(env, _exccls, msg);  \
 	goto bailout;  \
 }
 
-#define bailif0(f) {if(!(f)) {  \
-	char temps[80];  \
-	snprintf(temps, 80, "Unexpected NULL condition in line %d", __LINE__);  \
-	_throw(temps);  \
+#define _throwtj() _throw(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException")
+
+#define _throwarg(msg) _throw(msg, "java/lang/IllegalArgumentException")
+
+#define _throwmem() _throw("Memory allocation failure", "java/lang/OutOfMemoryError");
+
+#define bailif0(f) {if(!(f) || (*env)->ExceptionCheck(env)) {  \
+	goto bailout;  \
 }}
 
 #define gethandle()  \
 	jclass _cls=(*env)->GetObjectClass(env, obj);  \
 	jfieldID _fid;  \
-	if(!_cls) goto bailout;  \
+	if(!_cls || (*env)->ExceptionCheck(env)) goto bailout;  \
 	bailif0(_fid=(*env)->GetFieldID(env, _cls, "handle", "J"));  \
 	handle=(tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid);  \
 
@@ -101,7 +105,7 @@
 	(JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp)
 {
 	jint retval=(jint)tjBufSize(width, height, jpegSubsamp);
-	if(retval==-1) _throw(tjGetErrorStr());
+	if(retval==-1) _throwarg(tjGetErrorStr());
 
 	bailout:
 	return retval;
@@ -112,7 +116,7 @@
 	(JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp)
 {
 	jint retval=(jint)tjBufSizeYUV2(width, pad, height, subsamp);
-	if(retval==-1) _throw(tjGetErrorStr());
+	if(retval==-1) _throwarg(tjGetErrorStr());
 
 	bailout:
 	return retval;
@@ -133,7 +137,7 @@
 {
 	jint retval=(jint)tjPlaneSizeYUV(componentID, width, stride, height,
 		subsamp);
-	if(retval==-1) _throw(tjGetErrorStr());
+	if(retval==-1) _throwarg(tjGetErrorStr());
 
 	bailout:
 	return retval;
@@ -144,7 +148,7 @@
 	(JNIEnv *env, jclass cls, jint componentID, jint width, jint subsamp)
 {
 	jint retval=(jint)tjPlaneWidth(componentID, width, subsamp);
-	if(retval==-1) _throw(tjGetErrorStr());
+	if(retval==-1) _throwarg(tjGetErrorStr());
 
 	bailout:
 	return retval;
@@ -155,7 +159,7 @@
 	(JNIEnv *env, jclass cls, jint componentID, jint height, jint subsamp)
 {
 	jint retval=(jint)tjPlaneHeight(componentID, height, subsamp);
-	if(retval==-1) _throw(tjGetErrorStr());
+	if(retval==-1) _throwarg(tjGetErrorStr());
 
 	bailout:
 	return retval;
@@ -170,7 +174,7 @@
 	tjhandle handle;
 
 	if((handle=tjInitCompress())==NULL)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailif0(cls=(*env)->GetObjectClass(env, obj));
 	bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J"));
@@ -194,17 +198,17 @@
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
-		_throw("Invalid argument in compress()");
+		_throwarg("Invalid argument in compress()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch;
 	arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf];
 	if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize)
-		_throw("Source buffer is not large enough");
+		_throwarg("Source buffer is not large enough");
 	jpegSize=tjBufSize(width, height, jpegSubsamp);
 	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
@@ -214,7 +218,7 @@
 	if(tjCompress2(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]], width,
 		pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp, jpegQual,
 		flags|TJFLAG_NOREALLOC)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
@@ -249,9 +253,9 @@
 		jint jpegQual, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in compress()");
+		_throwarg("Invalid argument in compress()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when compressing from an integer buffer.");
+		_throwarg("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);
@@ -267,9 +271,9 @@
 		jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in compress()");
+		_throwarg("Invalid argument in compress()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when compressing from an integer buffer.");
+		_throwarg("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);
@@ -287,27 +291,28 @@
 	tjhandle handle=0;
 	unsigned long jpegSize=0;
 	jbyteArray jSrcPlanes[3]={NULL, NULL, NULL};
-	unsigned char *srcPlanes[3], *jpegBuf=NULL;
+	const unsigned char *srcPlanes[3];
+	unsigned char *jpegBuf=NULL;
 	int *srcOffsets=NULL, *srcStrides=NULL;
 	int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i;
 
 	gethandle();
 
 	if(subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
-		_throw("Invalid argument in compressFromYUV()");
+		_throwarg("Invalid argument in compressFromYUV()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	if((*env)->GetArrayLength(env, srcobjs)<nc)
-		_throw("Planes array is too small for the subsampling type");
+		_throwarg("Planes array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jSrcOffsets)<nc)
-		_throw("Offsets array is too small for the subsampling type");
+		_throwarg("Offsets array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jSrcStrides)<nc)
-		_throw("Strides array is too small for the subsampling type");
+		_throwarg("Strides array is too small for the subsampling type");
 
 	jpegSize=tjBufSize(width, height, subsamp);
 	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
 	bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
@@ -317,16 +322,16 @@
 		int pw=tjPlaneWidth(i, width, subsamp);
 
 		if(planeSize<0 || pw<0)
-			_throw(tjGetErrorStr());
+			_throwarg(tjGetErrorStr());
 
 		if(srcOffsets[i]<0)
-			_throw("Invalid argument in compressFromYUV()");
+			_throwarg("Invalid argument in compressFromYUV()");
 		if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0)
-			_throw("Negative plane stride would cause memory to be accessed below plane boundary");
+			_throwarg("Negative plane stride would cause memory to be accessed below plane boundary");
 
 		bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i));
 		if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize)
-			_throw("Source plane is not large enough");
+			_throwarg("Source plane is not large enough");
 
 		bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i],
 			0));
@@ -338,15 +343,15 @@
 
 	if(tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
 		subsamp, &jpegBuf, &jpegSize, jpegQual, flags|TJFLAG_NOREALLOC)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
 	for(i=0; i<nc; i++)
 	{
 		if(srcPlanes[i] && jSrcPlanes[i])
-			(*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i],
-				0);
+			(*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i],
+				(unsigned char *)srcPlanes[i], 0);
 	}
 	if(srcStrides)
 		(*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0);
@@ -371,22 +376,22 @@
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0 || subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
-		_throw("Invalid argument in encodeYUV()");
+		_throwarg("Invalid argument in encodeYUV()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF
 		|| org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	if((*env)->GetArrayLength(env, dstobjs)<nc)
-		_throw("Planes array is too small for the subsampling type");
+		_throwarg("Planes array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jDstOffsets)<nc)
-		_throw("Offsets array is too small for the subsampling type");
+		_throwarg("Offsets array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jDstStrides)<nc)
-		_throw("Strides array is too small for the subsampling type");
+		_throwarg("Strides array is too small for the subsampling type");
 
 	actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch;
 	arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf];
 	if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize)
-		_throw("Source buffer is not large enough");
+		_throwarg("Source buffer is not large enough");
 
 	bailif0(dstOffsets=(*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
 	bailif0(dstStrides=(*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
@@ -396,16 +401,16 @@
 		int pw=tjPlaneWidth(i, width, subsamp);
 
 		if(planeSize<0 || pw<0)
-			_throw(tjGetErrorStr());
+			_throwarg(tjGetErrorStr());
 
 		if(dstOffsets[i]<0)
-			_throw("Invalid argument in encodeYUV()");
+			_throwarg("Invalid argument in encodeYUV()");
 		if(dstStrides[i]<0 && dstOffsets[i]-planeSize+pw<0)
-			_throw("Negative plane stride would cause memory to be accessed below plane boundary");
+			_throwarg("Negative plane stride would cause memory to be accessed below plane boundary");
 
 		bailif0(jDstPlanes[i]=(*env)->GetObjectArrayElement(env, dstobjs, i));
 		if((*env)->GetArrayLength(env, jDstPlanes[i])<dstOffsets[i]+planeSize)
-			_throw("Destination plane is not large enough");
+			_throwarg("Destination plane is not large enough");
 
 		bailif0(dstPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i],
 			0));
@@ -415,7 +420,7 @@
 
 	if(tjEncodeYUVPlanes(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]],
 		width, pitch, height, pf, dstPlanes, dstStrides, subsamp, flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
@@ -445,13 +450,13 @@
 /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */
 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
 	(JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
-		jint stride, jint height, jint pf, jobjectArray dstobjs, 
+		jint stride, jint height, jint pf, jobjectArray dstobjs,
 		jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in encodeYUV()");
+		_throwarg("Invalid argument in encodeYUV()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when encoding from an integer buffer.");
+		_throwarg("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,
@@ -473,23 +478,23 @@
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
 		|| pitch<0)
-		_throw("Invalid argument in encodeYUV()");
+		_throwarg("Invalid argument in encodeYUV()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height;
 	if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize)
-		_throw("Source buffer is not large enough");
+		_throwarg("Source buffer is not large enough");
 	if((*env)->GetArrayLength(env, dst)
 		<(jsize)tjBufSizeYUV(width, height, subsamp))
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
 	if(tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
 		flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
@@ -512,9 +517,9 @@
 		jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in encodeYUV()");
+		_throwarg("Invalid argument in encodeYUV()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when encoding from an integer buffer.");
+		_throwarg("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);
@@ -531,7 +536,7 @@
 
 	gethandle();
 
-	if(tjDestroy(handle)==-1) _throw(tjGetErrorStr());
+	if(tjDestroy(handle)==-1) _throwtj();
 	(*env)->SetLongField(env, obj, _fid, 0);
 
 	bailout:
@@ -546,7 +551,7 @@
 	jfieldID fid;
 	tjhandle handle;
 
-	if((handle=tjInitDecompress())==NULL) _throw(tjGetErrorStr());
+	if((handle=tjInitDecompress())==NULL) _throwtj();
 
 	bailif0(cls=(*env)->GetObjectClass(env, obj));
 	bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J"));
@@ -566,7 +571,7 @@
 	jobjectArray sfjava=NULL;
 
 	if((sf=tjGetScalingFactors(&n))==NULL || n==0)
-		_throw(tjGetErrorStr());
+		_throwarg(tjGetErrorStr());
 
 	bailif0(sfcls=(*env)->FindClass(env, "org/libjpegturbo/turbojpeg/TJScalingFactor"));
 	bailif0(sfjava=(jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
@@ -596,13 +601,13 @@
 	gethandle();
 
 	if((*env)->GetArrayLength(env, src)<jpegSize)
-		_throw("Source buffer is not large enough");
+		_throwarg("Source buffer is not large enough");
 
 	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 
 	if(tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize,
 		&width, &height, &jpegSubsamp, &jpegColorspace)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	(*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);  jpegBuf=NULL;
 
@@ -634,16 +639,16 @@
 	gethandle();
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in decompress()");
+		_throwarg("Invalid argument in decompress()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	if((*env)->GetArrayLength(env, src)<jpegSize)
-		_throw("Source buffer is not large enough");
+		_throwarg("Source buffer is not large enough");
 	actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch;
 	arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf];
 	if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize)
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
@@ -651,7 +656,7 @@
 	if(tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize,
 		&dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf,
 		flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
@@ -683,9 +688,9 @@
 		jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in decompress()");
+		_throwarg("Invalid argument in decompress()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when decompressing to an integer buffer.");
+		_throwarg("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);
@@ -700,9 +705,9 @@
 		jint width, jint stride, jint height, jint pf, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in decompress()");
+		_throwarg("Invalid argument in decompress()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when decompressing to an integer buffer.");
+		_throwarg("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);
@@ -730,7 +735,7 @@
 	gethandle();
 
 	if((*env)->GetArrayLength(env, src)<jpegSize)
-		_throw("Source buffer is not large enough");
+		_throwarg("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"));
@@ -745,7 +750,7 @@
 	if(height==0) height=jpegHeight;
 	sf=tjGetScalingFactors(&nsf);
 	if(!sf || nsf<1)
-		_throw(tjGetErrorStr());
+		_throwarg(tjGetErrorStr());
 	for(i=0; i<nsf; i++)
 	{
 		scaledWidth=TJSCALED(jpegWidth, sf[i]);
@@ -763,16 +768,16 @@
 		int pw=tjPlaneWidth(i, scaledWidth, jpegSubsamp);
 
 		if(planeSize<0 || pw<0)
-			_throw(tjGetErrorStr());
+			_throwarg(tjGetErrorStr());
 
 		if(dstOffsets[i]<0)
-			_throw("Invalid argument in decompressToYUV()");
+			_throwarg("Invalid argument in decompressToYUV()");
 		if(dstStrides[i]<0 && dstOffsets[i]-planeSize+pw<0)
-			_throw("Negative plane stride would cause memory to be accessed below plane boundary");
+			_throwarg("Negative plane stride would cause memory to be accessed below plane boundary");
 
 		bailif0(jDstPlanes[i]=(*env)->GetObjectArrayElement(env, dstobjs, i));
 		if((*env)->GetArrayLength(env, jDstPlanes[i])<dstOffsets[i]+planeSize)
-			_throw("Destination plane is not large enough");
+			_throwarg("Destination plane is not large enough");
 
 		bailif0(dstPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i],
 			0));
@@ -782,7 +787,7 @@
 
 	if(tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
 		dstPlanes, desiredWidth, dstStrides, desiredHeight, flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0);
@@ -811,7 +816,7 @@
 	gethandle();
 
 	if((*env)->GetArrayLength(env, src)<jpegSize)
-		_throw("Source buffer is not large enough");
+		_throwarg("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"));
@@ -820,14 +825,14 @@
 	jpegHeight=(int)(*env)->GetIntField(env, obj, _fid);
 	if((*env)->GetArrayLength(env, dst)
 		<(jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp))
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
 	bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));
 
 	if(tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
 		flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
@@ -843,7 +848,8 @@
 	tjhandle handle=0;
 	jsize arraySize=0, actualPitch;
 	jbyteArray jSrcPlanes[3]={NULL, NULL, NULL};
-	unsigned char *srcPlanes[3], *dstBuf=NULL;
+	const unsigned char *srcPlanes[3];
+	unsigned char *dstBuf=NULL;
 	int *srcOffsets=NULL, *srcStrides=NULL;
 	int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i;
 
@@ -851,22 +857,22 @@
 
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp<0
 		|| subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
-		_throw("Invalid argument in decodeYUV()");
+		_throwarg("Invalid argument in decodeYUV()");
 	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF
 		|| org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP)
-		_throw("Mismatch between Java and C API");
+		_throwarg("Mismatch between Java and C API");
 
 	if((*env)->GetArrayLength(env, srcobjs)<nc)
-		_throw("Planes array is too small for the subsampling type");
+		_throwarg("Planes array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jSrcOffsets)<nc)
-		_throw("Offsets array is too small for the subsampling type");
+		_throwarg("Offsets array is too small for the subsampling type");
 	if((*env)->GetArrayLength(env, jSrcStrides)<nc)
-		_throw("Strides array is too small for the subsampling type");
+		_throwarg("Strides array is too small for the subsampling type");
 
 	actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch;
 	arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf];
 	if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize)
-		_throw("Destination buffer is not large enough");
+		_throwarg("Destination buffer is not large enough");
 
 	bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
 	bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
@@ -876,16 +882,16 @@
 		int pw=tjPlaneWidth(i, width, subsamp);
 
 		if(planeSize<0 || pw<0)
-			_throw(tjGetErrorStr());
+			_throwarg(tjGetErrorStr());
 
 		if(srcOffsets[i]<0)
-			_throw("Invalid argument in decodeYUV()");
+			_throwarg("Invalid argument in decodeYUV()");
 		if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0)
-			_throw("Negative plane stride would cause memory to be accessed below plane boundary");
+			_throwarg("Negative plane stride would cause memory to be accessed below plane boundary");
 
 		bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i));
 		if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize)
-			_throw("Source plane is not large enough");
+			_throwarg("Source plane is not large enough");
 
 		bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i],
 			0));
@@ -896,15 +902,15 @@
 	if(tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
 		&dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf,
 		flags)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	bailout:
 	if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0);
 	for(i=0; i<nc; i++)
 	{
 		if(srcPlanes[i] && jSrcPlanes[i])
-			(*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i],
-				0);
+			(*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i],
+				(unsigned char *)srcPlanes[i], 0);
 	}
 	if(srcStrides)
 		(*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0);
@@ -930,9 +936,9 @@
 		jint width, jint stride, jint height, jint pf, jint flags)
 {
 	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF)
-		_throw("Invalid argument in decodeYUV()");
+		_throwarg("Invalid argument in decodeYUV()");
 	if(tjPixelSize[pf]!=sizeof(jint))
-		_throw("Pixel format must be 32-bit when decoding to an integer buffer.");
+		_throwarg("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,
@@ -950,7 +956,7 @@
 	jfieldID fid;
 	tjhandle handle;
 
-	if((handle=tjInitTransform())==NULL) _throw(tjGetErrorStr());
+	if((handle=tjInitTransform())==NULL) _throwtj();
 
 	bailif0(cls=(*env)->GetObjectClass(env, obj));
 	bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J"));
@@ -1040,7 +1046,7 @@
 	gethandle();
 
 	if((*env)->GetArrayLength(env, jsrcBuf)<jpegSize)
-		_throw("Source buffer is not large enough");
+		_throwarg("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"));
@@ -1050,19 +1056,19 @@
 
 	n=(*env)->GetArrayLength(env, dstobjs);
 	if(n!=(*env)->GetArrayLength(env, tobjs))
-		_throw("Mismatch between size of transforms array and destination buffers array");
+		_throwarg("Mismatch between size of transforms array and destination buffers array");
 
 	if((dstBufs=(unsigned char **)malloc(sizeof(unsigned char *)*n))==NULL)
-		_throw("Memory allocation failure");
+		_throwmem();
 	if((jdstBufs=(jbyteArray *)malloc(sizeof(jbyteArray)*n))==NULL)
-		_throw("Memory allocation failure");
+		_throwmem();
 	if((dstSizes=(unsigned long *)malloc(sizeof(unsigned long)*n))==NULL)
-		_throw("Memory allocation failure");
+		_throwmem();
 	if((t=(tjtransform *)malloc(sizeof(tjtransform)*n))==NULL)
-		_throw("Memory allocation failure");
+		_throwmem();
 	if((params=(JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams)*n))
 		==NULL)
-		_throw("Memory allocation failure");
+		_throwmem();
 	for(i=0; i<n; i++)
 	{
 		dstBufs[i]=NULL;  jdstBufs[i]=NULL;  dstSizes[i]=0;
@@ -1110,7 +1116,7 @@
 		bailif0(jdstBufs[i]=(*env)->GetObjectArrayElement(env, dstobjs, i));
 		if((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i])
 			<tjBufSize(w, h, jpegSubsamp))
-			_throw("Destination buffer is not large enough");
+			_throwarg("Destination buffer is not large enough");
 	}
 	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
 	for(i=0; i<n; i++)
@@ -1118,7 +1124,7 @@
 
 	if(tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
 		flags|TJFLAG_NOREALLOC)==-1)
-		_throw(tjGetErrorStr());
+		_throwtj();
 
 	for(i=0; i<n; i++)
 	{
diff --git a/turbojpeg.c b/turbojpeg.c
index 6b2c623..5754cb1 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -44,7 +44,8 @@
 
 extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **,
 	unsigned long *, boolean);
-extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long);
+extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *,
+	unsigned long);
 
 #define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
 #define isPow2(x) (((x)&(x-1))==0)
@@ -728,7 +729,7 @@
 }
 
 
-DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
+DLLEXPORT int DLLCALL 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)
 {
@@ -785,8 +786,9 @@
 		_throw("tjCompress2(): Memory allocation failure");
 	for(i=0; i<height; i++)
 	{
-		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
-		else row_pointer[i]=&srcBuf[i*pitch];
+		if(flags&TJFLAG_BOTTOMUP)
+			row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
+		else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
 	}
 	while(cinfo->next_scanline<cinfo->image_height)
 	{
@@ -827,9 +829,10 @@
 }
 
 
-DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle, unsigned char *srcBuf,
-	int width, int pitch, int height, int pixelFormat, unsigned char **dstPlanes,
-	int *strides, int subsamp, int flags)
+DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
+	const unsigned char *srcBuf, int width, int pitch, int height,
+	int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
+	int flags)
 {
 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
 	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
@@ -910,8 +913,9 @@
 		_throw("tjEncodeYUVPlanes(): Memory allocation failure");
 	for(i=0; i<height; i++)
 	{
-		if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch];
-		else row_pointer[i]=&srcBuf[i*pitch];
+		if(flags&TJFLAG_BOTTOMUP)
+			row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch];
+		else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch];
 	}
 	if(height<ph0)
 		for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1];
@@ -988,9 +992,9 @@
 	return retval;
 }
 
-DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, unsigned char *srcBuf,
-	int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf,
-	int pad, int subsamp, int flags)
+DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
+	const unsigned char *srcBuf, int width, int pitch, int height,
+	int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags)
 {
 	unsigned char *dstPlanes[3];
 	int pw0, ph0, strides[3], retval=-1;
@@ -1042,8 +1046,9 @@
 
 
 DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
-	unsigned char **srcPlanes, int width, int *strides, int height, int subsamp,
-	unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)
+	const unsigned char **srcPlanes, int width, const int *strides, int height,
+	int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
+	int flags)
 {
 	int i, row, retval=0, alloc=1;  JSAMPROW *inbuf[MAX_COMPONENTS];
 	int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS],
@@ -1106,7 +1111,7 @@
 		tmpbufsize+=iw[i]*th[i];
 		if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL)
 			_throw("tjCompressFromYUVPlanes(): Memory allocation failure");
-		ptr=srcPlanes[i];
+		ptr=(JSAMPLE *)srcPlanes[i];
 		for(row=0; row<ph[i]; row++)
 		{
 			inbuf[i][row]=ptr;
@@ -1172,11 +1177,11 @@
 	return retval;
 }
 
-DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
-	int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
-	unsigned long *jpegSize, int jpegQual, int flags)
+DLLEXPORT int DLLCALL 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)
 {
-	unsigned char *srcPlanes[3];
+	const unsigned char *srcPlanes[3];
 	int pw0, ph0, strides[3], retval=-1;
 
 	if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
@@ -1251,8 +1256,8 @@
 
 
 DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
-	unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
-	int *jpegSubsamp, int *jpegColorspace)
+	const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
+	int *height, int *jpegSubsamp, int *jpegColorspace)
 {
 	int retval=0;
 
@@ -1332,9 +1337,9 @@
 }
 
 
-DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf,
-	unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch,
-	int height, int pixelFormat, int flags)
+DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
+	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+	int width, int pitch, int height, int pixelFormat, int flags)
 {
 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
 	int jpegwidth, jpegheight, scaledw, scaledh;
@@ -1500,8 +1505,9 @@
 }
 
 DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
-	unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf,
-	int width, int pitch, int height, int pixelFormat, int flags)
+	const unsigned char **srcPlanes, const int *strides, int subsamp,
+	unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
+	int flags)
 {
 	int i, retval=0;  JSAMPROW *row_pointer=NULL;
 	JSAMPLE *_tmpbuf[MAX_COMPONENTS];
@@ -1620,7 +1626,7 @@
 		ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor;
 		inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]);
 		if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure");
-		ptr=srcPlanes[i];
+		ptr=(JSAMPLE *)srcPlanes[i];
 		for(row=0; row<ph[i]; row++)
 		{
 			inbuf[i][row]=ptr;
@@ -1661,11 +1667,11 @@
 	return retval;
 }
 
-DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, unsigned char *srcBuf,
+DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
 	int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
 	int height, int pixelFormat, int flags)
 {
-	unsigned char *srcPlanes[3];
+	const unsigned char *srcPlanes[3];
 	int pw0, ph0, strides[3], retval=-1;
 
 	if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT
@@ -1698,8 +1704,8 @@
 }
 
 DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
-	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes,
-	int width, int *strides, int height, int flags)
+	const unsigned char *jpegBuf, unsigned long jpegSize,
+	unsigned char **dstPlanes, int width, int *strides, int height, int flags)
 {
 	int i, sfi, row, retval=0;  JSAMPROW *outbuf[MAX_COMPONENTS];
 	int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh;
@@ -1872,7 +1878,7 @@
 }
 
 DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
-	unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+	const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
 	int width, int pad, int height, int flags)
 {
 	unsigned char *dstPlanes[3];
@@ -1959,9 +1965,9 @@
 }
 
 
-DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
-	unsigned long jpegSize, int n, unsigned char **dstBufs,
-	unsigned long *dstSizes, tjtransform *t, int flags)
+DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
+	const unsigned char *jpegBuf, unsigned long jpegSize, int n,
+	unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags)
 {
 	jpeg_transform_info *xinfo=NULL;
 	jvirt_barray_ptr *srccoefs, *dstcoefs;
diff --git a/turbojpeg.h b/turbojpeg.h
index d5c624e..583029f 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -619,7 +619,7 @@
  * @param handle a handle to a TurboJPEG compressor or transformer instance
  *
  * @param srcBuf pointer to an image buffer containing RGB, grayscale, or
- * CMYK pixels to be compressed.  This buffer is not modified.
+ * CMYK pixels to be compressed
  *
  * @param width width (in pixels) of the source image
  *
@@ -672,7 +672,7 @@
  *
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
-DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
+DLLEXPORT int DLLCALL 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);
 
@@ -687,7 +687,7 @@
  * #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".)  This buffer is not modified.
+ * "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
@@ -736,9 +736,9 @@
  *
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
-DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
-  int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
-  unsigned long *jpegSize, int jpegQual, int flags);
+DLLEXPORT int DLLCALL 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);
 
 
 /**
@@ -752,7 +752,7 @@
  * 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.  These image planes are not modified.
+ * 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
@@ -807,8 +807,9 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
 DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle,
-  unsigned char **srcPlanes, int width, int *strides, int height, int subsamp,
-  unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags);
+  const unsigned char **srcPlanes, int width, const int *strides, int height,
+  int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual,
+  int flags);
 
 
 /**
@@ -926,7 +927,7 @@
  * @param handle a handle to a TurboJPEG compressor or transformer instance
  *
  * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded.  This buffer is not modified.
+ * to be encoded
  *
  * @param width width (in pixels) of the source image
  *
@@ -966,8 +967,8 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
 DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle,
-  unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat,
-  unsigned char *dstBuf, int pad, int subsamp, int flags);
+  const unsigned char *srcBuf, int width, int pitch, int height,
+  int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags);
 
 
 /**
@@ -979,7 +980,7 @@
  * @param handle a handle to a TurboJPEG compressor or transformer instance
  *
  * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded.  This buffer is not modified.
+ * to be encoded
  *
  * @param width width (in pixels) of the source image
  *
@@ -1024,8 +1025,9 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
 DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle,
-  unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat,
-  unsigned char **dstPlanes, int *strides, int subsamp, int flags);
+  const unsigned char *srcBuf, int width, int pitch, int height,
+  int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp,
+  int flags);
 
 
 /**
@@ -1042,8 +1044,7 @@
  *
  * @param handle a handle to a TurboJPEG decompressor or transformer instance
  *
- * @param jpegBuf pointer to a buffer containing a JPEG image.  This buffer is
- * not modified.
+ * @param jpegBuf pointer to a buffer containing a JPEG image
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
@@ -1064,8 +1065,8 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
 */
 DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle,
-  unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height,
-  int *jpegSubsamp, int *jpegColorspace);
+  const unsigned char *jpegBuf, unsigned long jpegSize, int *width,
+  int *height, int *jpegSubsamp, int *jpegColorspace);
 
 
 /**
@@ -1086,8 +1087,7 @@
  *
  * @param handle a handle to a TurboJPEG decompressor or transformer instance
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress.
- * This buffer is not modified.
+ * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
@@ -1132,7 +1132,7 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
 DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle,
-  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+  const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
   int width, int pitch, int height, int pixelFormat, int flags);
 
 
@@ -1143,8 +1143,7 @@
  *
  * @param handle a handle to a TurboJPEG decompressor or transformer instance
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress.
- * This buffer is not modified.
+ * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
@@ -1183,7 +1182,7 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
 DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
-  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
+  const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf,
   int width, int pad, int height, int flags);
 
 
@@ -1194,8 +1193,7 @@
  *
  * @param handle a handle to a TurboJPEG decompressor or transformer instance
  *
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress.
- * This buffer is not modified.
+ * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
  *
  * @param jpegSize size of the JPEG image (in bytes)
  *
@@ -1240,8 +1238,8 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
 DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle,
-  unsigned char *jpegBuf, unsigned long jpegSize, unsigned char **dstPlanes,
-  int width, int *strides, int height, int flags);
+  const unsigned char *jpegBuf, unsigned long jpegSize,
+  unsigned char **dstPlanes, int width, int *strides, int height, int flags);
 
 
 /**
@@ -1257,7 +1255,7 @@
  * #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".)  This buffer is not modified.
+ * "YUV Image Format Notes".)
  *
  * @param pad Use this parameter to specify that the width of each line in each
  * plane of the YUV source image is padded to the nearest multiple of this
@@ -1291,7 +1289,7 @@
  *
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
-DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, unsigned char *srcBuf,
+DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
   int pad, int subsamp, unsigned char *dstBuf, int width, int pitch,
   int height, int pixelFormat, int flags);
 
@@ -1310,7 +1308,7 @@
  * 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.  These image planes are not modified.
+ * 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
@@ -1349,8 +1347,9 @@
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
 DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle,
-  unsigned char **srcPlanes, int *strides, int subsamp, unsigned char *dstBuf,
-  int width, int pitch, int height, int pixelFormat, int flags);
+  const unsigned char **srcPlanes, const int *strides, int subsamp,
+  unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat,
+  int flags);
 
 
 /**
@@ -1378,7 +1377,7 @@
  * @param handle a handle to a TurboJPEG transformer instance
  *
  * @param jpegBuf pointer to a buffer containing the JPEG source image to
- * transform.  This buffer is not modified.
+ * transform
  *
  * @param jpegSize size of the JPEG source image (in bytes)
  *
@@ -1417,9 +1416,10 @@
  *
  * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
  */
-DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
-  unsigned long jpegSize, int n, unsigned char **dstBufs,
-  unsigned long *dstSizes, tjtransform *transforms, int flags);
+DLLEXPORT int DLLCALL tjTransform(tjhandle handle,
+  const unsigned char *jpegBuf, unsigned long jpegSize, int n,
+  unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms,
+  int flags);
 
 
 /**
diff --git a/win/jpeg62-memsrcdst.def b/win/jpeg62-memsrcdst.def
index 4511c8e..949d267 100755
--- a/win/jpeg62-memsrcdst.def
+++ b/win/jpeg62-memsrcdst.def
@@ -102,3 +102,4 @@
 	jzero_far @ 101 ; 
 	jpeg_mem_dest @ 102 ; 
 	jpeg_mem_src @ 103 ; 
+	jpeg_skip_scanlines @ 104 ; 
diff --git a/win/jpeg62.def b/win/jpeg62.def
index 3c33fbf..c64df50 100755
--- a/win/jpeg62.def
+++ b/win/jpeg62.def
@@ -100,3 +100,4 @@
 	jpeg_write_tables @ 99 ; 
 	jround_up @ 100 ; 
 	jzero_far @ 101 ; 
+	jpeg_skip_scanlines @ 102 ; 
diff --git a/win/jpeg7.def b/win/jpeg7.def
index 5ca227b..8daa35f 100644
--- a/win/jpeg7.def
+++ b/win/jpeg7.def
@@ -102,3 +102,4 @@
 	jpeg_write_tables @ 101 ; 
 	jround_up @ 102 ; 
 	jzero_far @ 103 ; 
+	jpeg_skip_scanlines @ 104 ; 
diff --git a/win/jpeg8.def b/win/jpeg8.def
index 3fa6111..01deb69 100644
--- a/win/jpeg8.def
+++ b/win/jpeg8.def
@@ -105,3 +105,4 @@
 	jpeg_write_tables @ 104 ; 
 	jround_up @ 105 ; 
 	jzero_far @ 106 ; 
+	jpeg_skip_scanlines @ 107 ;