Convert svn:ignore properties to .gitignore
diff --git a/BUILDING.txt b/BUILDING.txt
index 8f494db..01f67c1 100644
--- a/BUILDING.txt
+++ b/BUILDING.txt
@@ -1,7 +1,8 @@
 *******************************************************************************
-**     Building on Unix Platforms, Cygwin, and MinGW
+**     Building on Unix Platforms (including Cygwin)
 *******************************************************************************
 
+
 ==================
 Build Requirements
 ==================
@@ -9,9 +10,8 @@
 -- autoconf 2.56 or later
 -- automake 1.7 or later
 -- libtool 1.4 or later
-   * If using MinGW, these can be obtained by installing the MSYS DTK
 
--- NASM
+-- NASM (if building x86 or x86-64 SIMD extensions)
    * 0.98, or 2.01 or later is required for a 32-bit build
    * NASM 2.00 or later is required for a 64-bit build
    * NASM 2.07 or later is required for a 64-bit build on OS X.  This can be
@@ -34,36 +34,51 @@
 
 -- GCC v4.1 or later recommended for best performance
 
+
+==================
+Out-of-Tree Builds
+==================
+
+Binary objects, libraries, and executables are generated in the same directory
+from which configure was executed (the "binary directory"), and this directory
+need not necessarily be the same as the libjpeg-turbo source directory.  You
+can create multiple independent binary directories, in which different versions
+of libjpeg-turbo can be built from the same source tree using different
+compilers or settings.  In the sections below, {build_directory} refers to the
+binary directory, whereas {source_directory} refers to the libjpeg-turbo source
+directory.  For in-tree builds, these directories are the same.
+
+
 ======================
 Building libjpeg-turbo
 ======================
 
 The following procedure will build libjpeg-turbo on Linux, FreeBSD, 32-bit
-OS X, and Solaris/x86 systems (on Solaris, this generates a 32-bit library.
-See below for 64-bit build instructions.)
+OS X, Cygwin, and Solaris/x86 systems (on Solaris, this generates a 32-bit
+library.  See below for 64-bit build instructions.)
 
-  cd libjpeg-turbo
+  cd {source_directory}
   autoreconf -fiv
-  sh ./configure
+  cd {build_directory}
+  sh {source_directory}/configure [additional configure flags]
   make
 
-NOTE: Running autoreconf is only necessary if building libjpeg-turbo from the
-SVN repository.
+NOTE: Running autoreconf in the source directory is only necessary if building
+libjpeg-turbo from the SVN repository.
 
 This will generate the following files under .libs/
 
   libjpeg.a
       Static link library for libjpeg-turbo
 
-  libjpeg.so.62.0.0 (Linux, Solaris)
-  libjpeg.62.dylib (OS X)
-  libjpeg-62.dll (MinGW)
-  cygjpeg-62.dll (Cygwin)
+  libjpeg.so.{version} (Linux, Solaris)
+  libjpeg.{version}.dylib (OS X)
+  cygjpeg-{version}.dll (Cygwin)
       Shared library for libjpeg-turbo
 
   libjpeg.so (Linux, Solaris)
   libjpeg.dylib (OS X)
-  libjpeg.dll.a (Cygwin, MinGW)
+  libjpeg.dll.a (Cygwin)
       Development stub for libjpeg-turbo shared library
 
   libturbojpeg.a
@@ -73,13 +88,39 @@
   libturbojpeg.dylib (OS X)
       Shared library and development stub for TurboJPEG/OSS
 
-  libturbojpeg.dll (MinGW)
   cygturbojpeg.dll (Cygwin)
       Shared library for TurboJPEG/OSS
 
-  libturbojpeg.dll.a (Cygwin, MinGW)
+  libturbojpeg.dll.a (Cygwin)
       Development stub for TurboJPEG/OSS shared library
 
+{version} is 62.0.0, 7.0.0, or 8.0.2, depending on whether libjpeg v6b
+(default), v7, or v8 emulation is enabled.  If using Cygwin, {version} is
+62, 7, or 8.
+
+
+libjpeg v7 or v8 API/ABI Emulation
+----------------------------------
+
+Add --with-jpeg7 to the configure command line to build a version of
+libjpeg-turbo that is API/ABI-compatible with libjpeg v7.  Add --with-jpeg8 to
+the configure command to build a version of libjpeg-turbo that is
+API/ABI-compatible with libjpeg v8.  See README-turbo.txt for more information
+on libjpeg v7 and v8 emulation.
+
+
+Arithmetic Coding Support
+-------------------------
+
+Since the patent on arithmetic coding has expired, this functionality has been
+included in this release of libjpeg-turbo.  libjpeg-turbo's implementation is
+based on the implementation in libjpeg v8, but it works when emulating libjpeg
+v7 or v6b as well.  The default is to enable both arithmetic encoding and
+decoding, but those who have philosophical objections to arithmetic coding can
+add --without-arith-enc or --without-arith-dec to the configure command line to
+disable encoding or decoding (respectively.)
+
+
 ========================
 Installing libjpeg-turbo
 ========================
@@ -106,16 +147,18 @@
 to force applications to use libjpeg-turbo instead of libjpeg.  See
 README-turbo.txt for more information.
 
+
 =============
 Build Recipes
 =============
 
+
 32-bit Library Build on 64-bit Linux
 ------------------------------------
 
 Add
 
-  --host i686-pc-linux-gnu CFLAGS='-O3 -m32' CXXFLAGS='-O3 -m32' LDFLAGS=-m32
+  --host i686-pc-linux-gnu CFLAGS='-O3 -m32' LDFLAGS=-m32
 
 to the configure command line.
 
@@ -136,7 +179,7 @@
 
 Add
 
-  CFLAGS='-O3 -m32' CXXFLAGS='-O3 -m32' LDFLAGS=-m32
+  CFLAGS='-O3 -m32' LDFLAGS=-m32
 
 to the configure command line.
 
@@ -149,8 +192,6 @@
   --host x86_64-apple-darwin NASM=/opt/local/bin/nasm \
   CFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
     -mmacosx-version-min=10.4 -O3' \
-    CXXFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
-    -mmacosx-version-min=10.4 -O3' \
     LDFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
     -mmacosx-version-min=10.4'
 
@@ -165,8 +206,6 @@
 
   CFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
     -mmacosx-version-min=10.4 -O3 -m32' \
-    CXXFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
-    -mmacosx-version-min=10.4 -O3 -m32' \
     LDFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk \
     -mmacosx-version-min=10.4 -m32'
 
@@ -178,7 +217,7 @@
 
 Add
 
-  --host x86_64-pc-solaris CFLAGS='-O3 -m64' CXXFLAGS='-O3 -m64' LDFLAGS=-m64
+  --host x86_64-pc-solaris CFLAGS='-O3 -m64' LDFLAGS=-m64
 
 to the configure command line.
 
@@ -188,103 +227,299 @@
 
 Add
 
-  --host i386-unknown-freebsd CC='gcc -B /usr/lib32' CXX='g++ -B/usr/lib32' \
-    CFLAGS='-O3 -m32' CXXFLAGS='-O3 -m32' LDFLAGS='-B/usr/lib32'
+  --host i386-unknown-freebsd CC='gcc -B /usr/lib32' CFLAGS='-O3 -m32' \
+    LDFLAGS='-B/usr/lib32'
 
 to the configure command line.  NASM 2.07 or later from FreeBSD ports must be
 installed.
 
 
-MinGW Build on Cygwin
----------------------
-
-Add
-
-  --host mingw32
-
-to the configure command line.  This will produce libraries which do not
-depend on cygwin1.dll or other Cygwin DLL's.
-
-
 Sun Studio
 ----------
 
 Add
 
-  CC=cc CXX=CC
+  CC=cc
 
 to the configure command line.  libjpeg-turbo will automatically be built with
-the maximum optimization level (-xO5) unless you override CFLAGS and CXXFLAGS.
+the maximum optimization level (-xO5) unless you override CFLAGS.
 
 To build a 64-bit version of libjpeg-turbo using Sun Studio, add
 
-  --host x86_64-pc-solaris CC=cc CXX=CC CFLAGS='-xO5 -m64' \
-    CXXFLAGS='-xO5 -m64' LDFLAGS=-m64
+  --host x86_64-pc-solaris CC=cc CFLAGS='-xO5 -m64' LDFLAGS=-m64
 
 to the configure command line.
 
 
+MinGW Build on Cygwin
+---------------------
+
+Use CMake (see recipes below)
+
+
+
 *******************************************************************************
-**     Building on Windows (Visual C++)
+**     Building on Windows (Visual C++ or MinGW)
 *******************************************************************************
 
+
 ==================
 Build Requirements
 ==================
 
--- GNU Make v3.7 or later
-   * Can be found in MSYS (http://www.mingw.org/download.shtml) or
-     Cygwin (http://www.cygwin.com/)
+-- CMake (http://www.cmake.org) v2.6 or later
 
--- Windows SDK for Windows Server 2008 and .NET Framework 3.5 (or a later
-   version)
+-- Microsoft Visual C++ 2005 or later
 
-   http://msdn.microsoft.com/en-us/windows/dd146047.aspx
+   If you don't already have Visual C++, then the easiest way to get it is by
+   installing the Windows SDK:
 
-   * The Windows SDK includes both 32-bit and 64-bit Visual C++ compilers and
-     everything necessary to build libjpeg-turbo.  If you do not already have
-     Visual C++ installed, then this is the recommended solution.  Also tested
-     with Microsoft Visual C++ 2008 Express Edition (both are free downloads.)
-   * Add the compiler and SDK binary directories (for instance,
-     c:\Program Files\Microsoft Visual Studio 9.0\VC\BIN;
-     c:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE;
-     c:\Program Files\Microsoft SDKs\Windows\v6.1\bin)
-     to the system or user PATH environment variable prior to building
-     libjpeg-turbo.
-   * Add the compiler and SDK include directories (for instance,
-     c:\Program Files\Microsoft Visual Studio 9.0\VC\INCLUDE;
-     c:\Program Files\Microsoft SDKs\Windows\v6.1\include)
-     to the system or user INCLUDE environment variable prior to building
-     libjpeg-turbo.
-   * Add the compiler library directory (for instance,
-     c:\Program Files\Microsoft Visual Studio 9.0\VC\LIB;
-     c:\Program Files\Microsoft SDKs\Windows\v6.1\lib)
-     to the system or user LIB environment variable prior to building
-     libjpeg-turbo.
+   http://msdn.microsoft.com/en-us/windows/bb980924.aspx
+
+   The Windows SDK includes both 32-bit and 64-bit Visual C++ compilers and
+   everything necessary to build libjpeg-turbo.
+
+   * For 32-bit builds, you can also use Microsoft Visual C++ Express
+     Edition.  Visual C++ Express Edition is a free download.
+   * If you intend to build libjpeg-turbo from the command line, then add the
+     appropriate compiler and SDK directories to the INCLUDE, LIB, and PATH
+     environment variables.  This is generally accomplished by executing
+     vcvars32.bat or vcvars64.bat and SetEnv.cmd.  vcvars32.bat and
+     vcvars64.bat are part of Visual C++ and are located in the same directory
+     as the compiler.  SetEnv.cmd is part of the Windows SDK.  You can pass
+     optional arguments to SetEnv.cmd to specify a 32-bit or 64-bit build
+     environment.
+
+... OR ...
+
+-- MinGW
+
+   GCC v4.1 or later recommended for best performance
 
 -- NASM (http://www.nasm.us/) 0.98 or later (NASM 2.05 or later is required for
    a 64-bit build)
 
+
+==================
+Out-of-Tree Builds
+==================
+
+Binary objects, libraries, and executables are generated in the same directory
+from which cmake was executed (the "binary directory"), and this directory need
+not necessarily be the same as the libjpeg-turbo source directory.  You can
+create multiple independent binary directories, in which different versions of
+libjpeg-turbo can be built from the same source tree using different compilers
+or settings.  In the sections below, {build_directory} refers to the binary
+directory, whereas {source_directory} refers to the libjpeg-turbo source
+directory.  For in-tree builds, these directories are the same.
+
+
 ======================
 Building libjpeg-turbo
 ======================
 
-  cd libjpeg-turbo
-  make -f win/Makefile
 
-This will generate the following files under libjpeg-turbo\windows\:
+Visual C++ (Command Line)
+-------------------------
 
-  jpeg-static.lib        Static link library for libjpeg-turbo
-  jpeg62.dll             Shared library for libjpeg-turbo
-  jpeg.lib               Development stub for libjpeg-turbo shared library
-  turbojpeg-static.lib   Static link library for TurboJPEG/OSS
-  turbojpeg.dll          Shared library for TurboJPEG/OSS
-  turbojpeg.lib          Development stub for TurboJPEG/OSS shared library
+  cd {build_directory}
+  cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release {source_directory}
+  nmake
 
-If a 64-bit Windows platform is detected, then the build system will attempt
-to build a 64-bit version of libjpeg-turbo.  You can override this by running
+This will build either a 32-bit or a 64-bit version of libjpeg-turbo, depending
+on which version of cl.exe is in the PATH.
 
-  make -f win/Makefile WIN64=no
+The following files will be generated under {build_directory}:
+
+  jpeg-static.lib
+      Static link library for libjpeg-turbo
+  sharedlib/jpeg{version}.dll
+      DLL for libjpeg-turbo
+  sharedlib/jpeg.lib
+      Import library for libjpeg-turbo DLL
+  turbojpeg-static.lib
+      Static link library for TurboJPEG/OSS
+  turbojpeg.dll
+      DLL for TurboJPEG/OSS
+  turbojpeg.lib
+      Import library for TurboJPEG/OSS DLL
+
+{version} is 62, 7, or 8, depending on whether libjpeg v6b (default), v7, or
+v8 emulation is enabled.
+
+
+Visual C++ (IDE)
+----------------
+
+Choose the appropriate CMake generator option for your version of Visual Studio
+(run "cmake" with no arguments for a list of available generators.)  For
+instance:
+
+  cd {build_directory}
+  cmake -G "Visual Studio 9 2008" {source_directory}
+
+You can then open ALL_BUILD.vcproj in Visual Studio and build one of the
+configurations in that project ("Debug", "Release", etc.) to generate a full
+build of libjpeg-turbo.
+
+This will generate the following files under {build_directory}:
+
+  {configuration}/jpeg-static.lib
+      Static link library for libjpeg-turbo
+  sharedlib/{configuration}/jpeg{version}.dll
+      DLL for libjpeg-turbo
+  sharedlib/{configuration}/jpeg.lib
+      Import library for libjpeg-turbo DLL
+  {configuration}/turbojpeg-static.lib
+      Static link library for TurboJPEG/OSS
+  {configuration}/turbojpeg.dll
+      DLL for TurboJPEG/OSS
+  {configuration}/turbojpeg.lib
+      Import library for TurboJPEG/OSS DLL
+
+{configuration} is Debug, Release, RelWithDebInfo, or MinSizeRel, depending on
+the configuration you built in the IDE, and {version} is 62, 7, or 8,
+depending on whether libjpeg v6b (default), v7, or v8 emulation is enabled.
+
+
+MinGW
+-----
+
+  cd {build_directory}
+  cmake -G "MSYS Makefiles" {source_directory}
+  make
+
+This will generate the following files under {build_directory}
+
+  libjpeg.a
+      Static link library for libjpeg-turbo
+  sharedlib/libjpeg-{version}.dll
+      DLL for libjpeg-turbo
+  sharedlib/libjpeg.dll.a
+      Import library for libjpeg-turbo DLL
+  libturbojpeg.a
+      Static link library for TurboJPEG/OSS
+  libturbojpeg.dll
+      DLL for TurboJPEG/OSS
+  libturbojpeg.dll.a
+      Import library for TurboJPEG/OSS DLL
+
+{version} is 62, 7, or 8, depending on whether libjpeg v6b (default), v7, or
+v8 emulation is enabled.
+
+
+Debug Build
+-----------
+
+Add "-DCMAKE_BUILD_TYPE=Debug" to the cmake command line.  Or, if building with
+NMake, remove "-DCMAKE_BUILD_TYPE=Release" (Debug builds are the default with
+NMake.)
+
+
+libjpeg v7 or v8 API/ABI Emulation
+-----------------------------------
+
+Add "-DWITH_JPEG7=1" to the cmake command line to build a version of
+libjpeg-turbo that is API/ABI-compatible with libjpeg v7.  Add "-DWITH_JPEG8=1"
+to the cmake command to build a version of libjpeg-turbo that is
+API/ABI-compatible with libjpeg v8.  See README-turbo.txt for more information
+on libjpeg v7 and v8 emulation.
+
+
+Arithmetic Coding Support
+-------------------------
+
+Since the patent on arithmetic coding has expired, this functionality has been
+included in this release of libjpeg-turbo.  libjpeg-turbo's implementation is
+based on the implementation in libjpeg v8, but it works when emulating libjpeg
+v7 or v6b as well.  The default is to enable both arithmetic encoding and
+decoding, but those who have philosophical objections to arithmetic coding can
+add "-DWITH_ARITH_ENC=0" or "-DWITH_ARITH_DEC=0" to the cmake command line to
+disable encoding or decoding (respectively.)
+
+
+========================
+Installing libjpeg-turbo
+========================
+
+You can use the build system to install libjpeg-turbo into a directory of your
+choosing (as opposed to creating an installer.)  To do this, add:
+
+  -DCMAKE_INSTALL_PREFIX={install_directory}
+
+to the cmake command line.
+
+For example,
+
+  cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release \
+    -DCMAKE_INSTALL_PREFIX=c:\libjpeg-turbo {source_directory}
+  nmake install
+
+will install the header files in c:\libjpeg-turbo\include, the library files
+in c:\libjpeg-turbo\lib, the DLL's in c:\libjpeg-turbo\bin, and the
+documentation in c:\libjpeg-turbo\doc.
+
+
+=============
+Build Recipes
+=============
+
+
+64-bit MinGW Build on Cygwin
+----------------------------
+
+  cd {build_directory}
+  CC=/usr/bin/x86_64-w64-mingw32-gcc \
+    cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
+    -DCMAKE_AR=/usr/bin/x86_64-w64-mingw32-ar \
+    -DCMAKE_RANLIB=/usr/bin/x86_64-w64-mingw32-ranlib {source_directory}
+  make
+
+This produces a 64-bit build of libjpeg-turbo that does not depend on
+cygwin1.dll or other Cygwin DLL's.  The mingw64-x86_64-gcc-core and
+mingw64-x86_64-gcc-g++ packages (and their dependencies) must be installed.
+
+
+32-bit MinGW Build on Cygwin
+----------------------------
+
+  cd {build_directory}
+  CC=/usr/bin/i686-w64-mingw32-gcc \
+    cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
+    -DDCMAKE_AR=/usr/bin/i686-w64-mingw32-ar \
+    -DCMAKE_RANLIB=/usr/bin/i686-w64-mingw32-ranlib {source_directory}
+  make
+
+This produces a 32-bit build of libjpeg-turbo that does not depend on
+cygwin1.dll or other Cygwin DLL's.  The mingw64-i686-gcc-core and
+mingw64-i686-gcc-g++ packages (and their dependencies) must be installed.
+
+
+MinGW-w64 Build on Windows
+--------------------------
+
+This produces a 64-bit build of libjpeg-turbo using the "native" MinGW-w64
+toolchain (which is faster than the Cygwin version):
+
+  cd {build_directory}
+  CC={mingw-w64_binary_path}/x86_64-w64-mingw32-gcc \
+    cmake -G "MSYS Makefiles" \
+    -DCMAKE_AR={mingw-w64_binary_path}/x86_64-w64-mingw32-ar \
+    -DCMAKE_RANLIB={mingw-w64_binary_path}/x86_64-w64-mingw32-ranlib \
+    {source_directory}
+  make
+
+
+MinGW Build on Linux
+--------------------
+
+  cd {build_directory}
+  CC={mingw_binary_path}/i386-mingw32-gcc \
+    cmake -G "Unix Makefiles" -DCMAKE_SYSTEM_NAME=Windows \
+    -DCMAKE_AR={mingw_binary_path}/i386-mingw32-ar \
+    -DCMAKE_RANLIB={mingw_binary_path}/i386-mingw32-ranlib \
+    {source_directory}
+  make
 
 
 *******************************************************************************
@@ -293,14 +528,18 @@
 
 The following commands can be used to create various types of release packages:
 
+
+Unix
+----
+
 make rpm
 
-  Create RedHat-style binary RPM package.  Requires RPM v4 or later.
+  Create Red Hat-style binary RPM package.  Requires RPM v4 or later.
 
 make srpm
 
   This runs 'make dist' to create a pristine source tarball, then creates a
-  RedHat-style source RPM package from the tarball.  Requires RPM v4 or later.
+  Red Hat-style source RPM package from the tarball.  Requires RPM v4 or later.
 
 make deb
 
@@ -311,22 +550,55 @@
   Create Macintosh package/disk image.  This requires the PackageMaker
   application, which must be installed in /Developer/Applications/Utilities.
 
-make udmg
+make udmg [BUILDDIR32={32-bit build directory}]
 
   On 64-bit OS X systems, this creates a version of the Macintosh package and
-  disk image which contains universal i386/x86-64 binaries.  The 32-bit fork of
-  these binaries is backward compatible with OS X 10.4 and later.  The 64-bit
-  fork can be made backward compatible as well by using the instructions in
-  the "Build Recipes" section.  OS X 10.4 compatibility SDK required.
+  disk image that contains universal i386/x86-64 binaries.  You should first
+  configure a 32-bit out-of-tree build of libjpeg-turbo, then configure a
+  64-bit out-of-tree build, then run 'make udmg' from the 64-bit build
+  directory.  The build system will look for the 32-bit build under
+  {source_directory}/osxx86 by default, but you can override this by setting
+  the BUILDDIR32 variable on the make command line as shown above.
 
-make nsi
+make sunpkg
 
-  When using MinGW, this creates a Win32 installer for the GCC version of the
-  libjpeg-turbo SDK.  This requires the Nullsoft Install System
-  (http://nsis.sourceforge.net/.)  makensis.exe should be in your PATH.
+  Build a Solaris package.  This requires pkgmk, pkgtrans, and bzip2.
 
-make -f win/Makefile nsi
+make csunpkg [BUILDDIR32={32-bit build directory}]
 
-  This creates a Win32 installer for the Visual C++ version of the
-  libjpeg-turbo SDK.  This requires the Nullsoft Install System
-  (http://nsis.sourceforge.net/.)  makensis.exe should be in your PATH.
+  On 64-bit Solaris systems, this creates a combined package that contains
+  both 32-bit and 64-bit libraries.  You should first configure a 32-bit
+  out-of-tree build of libjpeg-turbo, then configure a 64-bit out-of-tree
+  build, then run 'make csunpkg' from the 64-bit build directory.  The build
+  system will look for the 32-bit build under {source_directory}/solx86 by
+  default, but you can override this by setting the BUILDDIR32 variable on the
+  make command line as shown above.
+
+make cygwinpkg
+
+  Build a Cygwin binary package.
+
+
+Windows
+-------
+
+If using NMake:
+
+  cd {build_directory}
+  nmake installer
+
+If using MinGW:
+
+  cd {build_directory}
+  make installer
+
+If using the Visual Studio IDE, build the "installer" project.
+
+The installer package (libjpeg-turbo[-gcc][64].exe) will be located under
+{build_directory}.  If building using the Visual Studio IDE, then the installer
+package will be located in a subdirectory with the same name as the
+configuration you built (such as {build_directory}\Debug\ or
+{build_directory}\Release\).
+
+Building a Windows installer requires the Nullsoft Install System
+(http://nsis.sourceforge.net/.)  makensis.exe should be in your PATH.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..6229ea0
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,352 @@
+#
+# Setup
+#
+
+cmake_minimum_required(VERSION 2.6)
+
+project(libjpeg-turbo C)
+set(VERSION 1.1.2)
+
+if(MINGW OR CYGWIN)
+  execute_process(COMMAND "date" "+%Y%m%d" OUTPUT_VARIABLE BUILD)
+  string(REGEX REPLACE "\n" "" BUILD ${BUILD})
+elseif(WIN32)
+  execute_process(COMMAND "wmic.exe" "os" "get" "LocalDateTime" OUTPUT_VARIABLE
+    BUILD)
+  string(REGEX REPLACE "[^0-9]" "" BUILD "${BUILD}")
+  if (BUILD STREQUAL "")
+    execute_process(COMMAND "cmd.exe" "/C" "DATE" "/T" OUTPUT_VARIABLE BUILD)
+    string(REGEX REPLACE ".*[ ]([0-9]*)[/.]([0-9]*)[/.]([0-9]*).*" "\\3\\2\\1" BUILD "${BUILD}")
+  else()
+    string(SUBSTRING "${BUILD}" 0 8 BUILD)
+  endif()
+else()
+  message(FATAL_ERROR "Platform not supported by this build system.  Use autotools instead.")
+endif()
+
+# This does nothing except when using MinGW.  CMAKE_BUILD_TYPE has no meaning
+# in Visual Studio, and it always defaults to Debug when using NMake.
+if(NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE Release)
+endif()
+
+message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
+
+# This only works if building from the command line.  There is currently no way
+# to set a variable's value based on the build type when using Visual Studio.
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+  set(BUILD "${BUILD}d")
+endif()
+
+message(STATUS "VERSION = ${VERSION}, BUILD = ${BUILD}")
+
+option(WITH_SIMD "Include SIMD extensions" TRUE)
+option(WITH_ARITH_ENC "Include arithmetic encoding support" TRUE)
+option(WITH_ARITH_DEC "Include arithmetic decoding support" TRUE)
+option(WITH_JPEG7 "Emulate libjpeg v7 API/ABI (this makes libjpeg-turbo backward incompatible with libjpeg v6b)" FALSE)
+option(WITH_JPEG8 "Emulate libjpeg v8 API/ABI (this makes libjpeg-turbo backward incompatible with libjpeg v6b)" FALSE)
+
+if(WITH_ARITH_ENC)
+  set(C_ARITH_CODING_SUPPORTED 1)
+  message(STATUS "Arithmetic encoding support enabled")
+else()
+  message(STATUS "Arithmetic encoding support disabled")
+endif()
+
+if(WITH_ARITH_DEC)
+  set(D_ARITH_CODING_SUPPORTED 1)
+  message(STATUS "Arithmetic decoding support enabled")
+else()
+  message(STATUS "Arithmetic decoding support disabled")
+endif()
+
+set(JPEG_LIB_VERSION 62)
+set(DLL_VERSION ${JPEG_LIB_VERSION})
+set(FULLVERSION ${DLL_VERSION}.0.0)
+if(WITH_JPEG8)
+  set(JPEG_LIB_VERSION 80)
+  set(DLL_VERSION 8)
+  set(FULLVERSION ${DLL_VERSION}.0.2)
+  message(STATUS "Emulating libjpeg v8 API/ABI")
+elseif(WITH_JPEG7)
+  set(JPEG_LIB_VERSION 70)
+  set(DLL_VERSION 7)
+  set(FULLVERSION ${DLL_VERSION}.0.0)
+  message(STATUS "Emulating libjpeg v7 API/ABI")
+endif(WITH_JPEG8)
+
+if(MSVC)
+  # Use the static C library for all build types
+  foreach(var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+    if(${var} MATCHES "/MD")
+      string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")
+    endif()
+  endforeach()
+
+  add_definitions(-W3 -wd4996)
+endif()
+
+# Detect whether compiler is 64-bit
+if(MSVC AND CMAKE_CL_64)
+  set(SIMD_X86_64 1)
+  set(64BIT 1)
+elseif(CMAKE_SIZEOF_VOID_P MATCHES 8)
+  set(SIMD_X86_64 1)
+  set(64BIT 1)
+endif()
+
+if(64BIT)
+  message(STATUS "64-bit build")
+else()
+  message(STATUS "32-bit build")
+endif()
+
+configure_file(win/jconfig.h.in jconfig.h)
+configure_file(win/config.h.in config.h)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
+
+
+#
+# Targets
+#
+
+set(JPEG_SOURCES jcapimin.c jcapistd.c jccoefct.c jccolor.c jcdctmgr.c jchuff.c
+  jcinit.c jcmainct.c jcmarker.c jcmaster.c jcomapi.c jcparam.c jcphuff.c
+  jcprepct.c jcsample.c jctrans.c jdapimin.c jdapistd.c jdatadst.c jdatasrc.c
+  jdcoefct.c jdcolor.c jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c
+  jdmaster.c jdmerge.c jdphuff.c jdpostct.c jdsample.c jdtrans.c jerror.c
+  jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jidctred.c
+  jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c)
+
+if(WITH_ARITH_ENC OR WITH_ARITH_DEC)
+  set(JPEG_SOURCES ${JPEG_SOURCES} jaricom.c)
+endif()
+
+if(WITH_ARITH_ENC)
+  set(JPEG_SOURCES ${JPEG_SOURCES} jcarith.c)
+endif()
+
+if(WITH_ARITH_DEC)
+  set(JPEG_SOURCES ${JPEG_SOURCES} jdarith.c)
+endif()
+
+if(WITH_SIMD)
+  add_definitions(-DWITH_SIMD)
+  add_subdirectory(simd)
+  if(SIMD_X86_64)
+    set(JPEG_SOURCES ${JPEG_SOURCES} simd/jsimd_x86_64.c)
+  else()
+    set(JPEG_SOURCES ${JPEG_SOURCES} simd/jsimd_i386.c)
+  endif()
+  # This tells CMake that the "source" files haven't been generated yet
+  set_source_files_properties(${SIMD_OBJS} PROPERTIES GENERATED 1)
+else()
+  set(JPEG_SOURCES ${JPEG_SOURCES} jsimd_none.c)
+  message(STATUS "Not using SIMD acceleration")
+endif()
+
+add_subdirectory(sharedlib)
+
+add_library(jpeg-static STATIC ${JPEG_SOURCES} ${SIMD_OBJS})
+if(NOT MSVC)
+  set_target_properties(jpeg-static PROPERTIES OUTPUT_NAME jpeg)
+endif()
+if(WITH_SIMD)
+  add_dependencies(jpeg-static simd)
+endif()
+
+add_library(turbojpeg SHARED turbojpegl.c)
+set_target_properties(turbojpeg PROPERTIES DEFINE_SYMBOL DLLDEFINE)
+target_link_libraries(turbojpeg jpeg-static)
+set_target_properties(turbojpeg PROPERTIES LINK_INTERFACE_LIBRARIES "")
+
+add_library(turbojpeg-static STATIC ${JPEG_SOURCES} ${SIMD_OBJS}
+  turbojpegl.c)
+if(NOT MSVC)
+  set_target_properties(turbojpeg-static PROPERTIES OUTPUT_NAME turbojpeg)
+endif()
+if(WITH_SIMD)
+  add_dependencies(turbojpeg-static simd)
+endif()
+
+add_executable(jpegut jpegut.c)
+target_link_libraries(jpegut turbojpeg)
+
+add_executable(jpegut-static jpegut.c)
+target_link_libraries(jpegut-static turbojpeg-static)
+
+add_executable(jpgtest jpgtest.c bmp.c)
+target_link_libraries(jpgtest turbojpeg)
+
+add_executable(jpgtest-static jpgtest.c bmp.c)
+target_link_libraries(jpgtest-static turbojpeg-static)
+
+add_executable(cjpeg-static cjpeg.c cdjpeg.c rdbmp.c rdgif.c rdppm.c rdswitch.c
+  rdtarga.c)
+set_property(TARGET cjpeg-static PROPERTY COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED -DUSE_SETMODE")
+target_link_libraries(cjpeg-static jpeg-static)
+
+add_executable(djpeg-static djpeg.c cdjpeg.c rdcolmap.c rdswitch.c wrbmp.c wrgif.c
+  wrppm.c wrtarga.c)
+set_property(TARGET djpeg-static PROPERTY COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED -DUSE_SETMODE")
+target_link_libraries(djpeg-static jpeg-static)
+
+add_executable(jpegtran-static jpegtran.c cdjpeg.c rdswitch.c transupp.c)
+target_link_libraries(jpegtran-static jpeg-static)
+set_property(TARGET jpegtran-static PROPERTY COMPILE_FLAGS "-DUSE_SETMODE")
+
+add_executable(rdjpgcom rdjpgcom.c)
+
+add_executable(wrjpgcom rdjpgcom.c)
+
+
+#
+# Tests
+#
+
+enable_testing()
+add_test(jpegut jpegut)
+add_test(jpegut-yuv jpegut -yuv)
+add_test(cjpeg-int sharedlib/cjpeg -dct int -outfile testoutint.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-int-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testoutint.jpg)
+add_test(cjpeg-fast sharedlib/cjpeg -dct fast -opt -outfile testoutfst.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-fast-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst.jpg testoutfst.jpg)
+add_test(cjpeg-fast-100 sharedlib/cjpeg -dct fast -quality 100 -opt -outfile testoutfst100.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-fast-100-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst100.jpg testoutfst100.jpg)
+add_test(cjpeg-float sharedlib/cjpeg -dct float -outfile testoutflt.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+if(WITH_SIMD)
+add_test(cjpeg-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt.jpg testoutflt.jpg)
+else()
+add_test(cjpeg-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt-nosimd.jpg testoutflt.jpg)
+endif()
+add_test(djpeg-int sharedlib/djpeg -dct int -fast -ppm -outfile testoutint.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-int-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.ppm testoutint.ppm)
+add_test(djpeg-fast sharedlib/djpeg -dct fast -ppm -outfile testoutfst.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-fast-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst.ppm testoutfst.ppm)
+add_test(djpeg-float sharedlib/djpeg -dct float -ppm -outfile testoutflt.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+if(WITH_SIMD)
+add_test(djpeg-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt.ppm testoutflt.ppm)
+else()
+add_test(djpeg-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testorig.ppm testoutflt.ppm)
+endif()
+add_test(djpeg-256 sharedlib/djpeg -dct int -bmp -colors 256 -outfile testout.bmp  ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-256-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimg.bmp testout.bmp)
+add_test(cjpeg-prog sharedlib/cjpeg -dct int -progressive -outfile testoutp.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-prog-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgp.jpg testoutp.jpg)
+add_test(jpegtran-prog sharedlib/jpegtran -outfile testoutt.jpg testoutp.jpg)
+add_test(jpegtran-prog-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testoutt.jpg)
+if(WITH_ARITH_ENC)
+add_test(cjpeg-ari sharedlib/cjpeg -dct int -arithmetic -outfile testoutari.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-ari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.jpg testoutari.jpg)
+add_test(jpegtran-toari sharedlib/jpegtran -arithmetic -outfile testouta.jpg ${CMAKE_SOURCE_DIR}/testimgint.jpg)
+add_test(jpegtran-toari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.jpg testouta.jpg)
+endif()
+if(WITH_ARITH_DEC)
+add_test(djpeg-ari sharedlib/djpeg -dct int -fast -ppm -outfile testoutari.ppm ${CMAKE_SOURCE_DIR}/testimgari.jpg)
+add_test(djpeg-ari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.ppm testoutari.ppm)
+add_test(jpegtran-fromari	sharedlib/jpegtran -outfile testouta.jpg ${CMAKE_SOURCE_DIR}/testimgari.jpg)
+add_test(jpegtran-fromari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testouta.jpg)
+endif()
+add_test(jpegtran-crop sharedlib/jpegtran -crop 120x90+20+50 -transpose -perfect -outfile testoutcrop.jpg ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(jpegtran-crop-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgcrop.jpg testoutcrop.jpg)
+
+add_test(jpegut-static jpegut-static)
+add_test(jpegut-static-yuv jpegut-static -yuv)
+add_test(cjpeg-static-int cjpeg-static -dct int -outfile testoutint.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-static-int-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testoutint.jpg)
+add_test(cjpeg-static-fast cjpeg-static -dct fast -opt -outfile testoutfst.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-static-fast-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst.jpg testoutfst.jpg)
+add_test(cjpeg-static-fast-100 cjpeg-static -dct fast -quality 100 -opt -outfile testoutfst100.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-static-fast-100-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst100.jpg testoutfst100.jpg)
+add_test(cjpeg-static-float cjpeg-static -dct float -outfile testoutflt.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+if(WITH_SIMD)
+add_test(cjpeg-static-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt.jpg testoutflt.jpg)
+else()
+add_test(cjpeg-static-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt-nosimd.jpg testoutflt.jpg)
+endif()
+add_test(djpeg-static-int djpeg-static -dct int -fast -ppm -outfile testoutint.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-static-int-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.ppm testoutint.ppm)
+add_test(djpeg-static-fast djpeg-static -dct fast -ppm -outfile testoutfst.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-static-fast-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgfst.ppm testoutfst.ppm)
+add_test(djpeg-static-float djpeg-static -dct float -ppm -outfile testoutflt.ppm ${CMAKE_SOURCE_DIR}/testorig.jpg)
+if(WITH_SIMD)
+add_test(djpeg-static-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgflt.ppm testoutflt.ppm)
+else()
+add_test(djpeg-static-float-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testorig.ppm testoutflt.ppm)
+endif()
+add_test(djpeg-static-256 djpeg-static -dct int -bmp -colors 256 -outfile testout.bmp  ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(djpeg-static-256-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimg.bmp testout.bmp)
+add_test(cjpeg-static-prog cjpeg-static -dct int -progressive -outfile testoutp.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-static-prog-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgp.jpg testoutp.jpg)
+add_test(jpegtran-static-prog jpegtran-static -outfile testoutt.jpg testoutp.jpg)
+add_test(jpegtran-static-prog-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testoutt.jpg)
+if(WITH_ARITH_ENC)
+add_test(cjpeg-static-ari cjpeg-static -dct int -arithmetic -outfile testoutari.jpg ${CMAKE_SOURCE_DIR}/testorig.ppm)
+add_test(cjpeg-static-ari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.jpg testoutari.jpg)
+add_test(jpegtran-static-toari jpegtran-static -arithmetic -outfile testouta.jpg ${CMAKE_SOURCE_DIR}/testimgint.jpg)
+add_test(jpegtran-static-toari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.jpg testouta.jpg)
+endif()
+if(WITH_ARITH_DEC)
+add_test(djpeg-static-ari djpeg-static -dct int -fast -ppm -outfile testoutari.ppm ${CMAKE_SOURCE_DIR}/testimgari.jpg)
+add_test(djpeg-static-ari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgari.ppm testoutari.ppm)
+add_test(jpegtran-static-fromari	jpegtran-static -outfile testouta.jpg ${CMAKE_SOURCE_DIR}/testimgari.jpg)
+add_test(jpegtran-static-fromari-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgint.jpg testouta.jpg)
+endif()
+add_test(jpegtran-static-crop jpegtran-static -crop 120x90+20+50 -transpose -perfect -outfile testoutcrop.jpg ${CMAKE_SOURCE_DIR}/testorig.jpg)
+add_test(jpegtran-static-crop-cmp ${CMAKE_COMMAND} -E compare_files ${CMAKE_SOURCE_DIR}/testimgcrop.jpg testoutcrop.jpg)
+
+
+#
+# Installer
+#
+
+if(MSVC)
+  set(INST_PLATFORM "Visual C++")
+  set(INST_NAME ${CMAKE_PROJECT_NAME}-${VERSION}-vc)
+  set(INST_DIR ${CMAKE_PROJECT_NAME})
+elseif(MINGW)
+  set(INST_PLATFORM GCC)
+  set(INST_NAME ${CMAKE_PROJECT_NAME}-${VERSION}-gcc)
+  set(INST_DIR ${CMAKE_PROJECT_NAME}-gcc)
+  set(INST_DEFS -DGCC)
+endif()
+
+if(64BIT)
+  set(INST_PLATFORM "${INST_PLATFORM} 64-bit")
+  set(INST_NAME ${INST_NAME}64)
+  set(INST_DIR ${INST_DIR}64)
+  set(INST_DEFS ${INST_DEFS} -DWIN64)
+endif()
+
+if(MSVC_IDE)
+  set(INST_DEFS ${INST_DEFS} "-DBUILDDIR=${CMAKE_CFG_INTDIR}\\")
+else()
+  set(INST_DEFS ${INST_DEFS} "-DBUILDDIR=")
+endif()
+
+configure_file(release/libjpeg-turbo.nsi.in libjpeg-turbo.nsi @ONLY)
+
+add_custom_target(installer
+  makensis -nocd ${INST_DEFS} libjpeg-turbo.nsi
+  DEPENDS jpeg jpeg-static turbojpeg turbojpeg-static rdjpgcom wrjpgcom
+    cjpeg djpeg jpegtran jpgtest
+  SOURCES libjpeg-turbo.nsi)
+
+install(TARGETS jpeg-static turbojpeg turbojpeg-static rdjpgcom wrjpgcom jpgtest
+  ARCHIVE DESTINATION lib
+  LIBRARY DESTINATION lib
+  RUNTIME DESTINATION bin
+)
+
+install(FILES ${CMAKE_SOURCE_DIR}/LGPL.txt ${CMAKE_SOURCE_DIR}/LICENSE.txt
+  ${CMAKE_SOURCE_DIR}/README ${CMAKE_SOURCE_DIR}/README-turbo.txt
+  ${CMAKE_SOURCE_DIR}/libjpeg.txt ${CMAKE_SOURCE_DIR}/usage.txt
+  DESTINATION doc)
+
+install(FILES ${CMAKE_BINARY_DIR}/jconfig.h ${CMAKE_SOURCE_DIR}/jerror.h
+  ${CMAKE_SOURCE_DIR}/jmorecfg.h ${CMAKE_SOURCE_DIR}/jpeglib.h
+  ${CMAKE_SOURCE_DIR}/turbojpeg.h DESTINATION include)
diff --git a/ChangeLog.txt b/ChangeLog.txt
index d482563..00441d2 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -1,32 +1,46 @@
-1.0.2
+1.1.2
 =====
 
-[1] Added further protections against invalid Huffman codes.
+[1] Eliminated errors in the output of jpegtran on Windows that occurred when
+the application was invoked using I/O redirection
+(jpegtran <input.jpg >output.jpg).
 
-[2] The algorithm used by the SIMD quantization function cannot produce correct
-results when the JPEG quality is >= 98 and the fast integer forward DCT is
-used.  Thus, the non-SIMD quantization function is now used for those cases,
-and libjpeg-turbo should now produce identical output to libjpeg v6b in all
-cases.
+[2] The inclusion of libjpeg v7 and v8 emulation as well as arithmetic coding
+support in libjpeg-turbo v1.1.0 introduced several new error constants in
+jerror.h, and these were mistakenly enabled for all emulation modes, causing
+the error enum in libjpeg-turbo to sometimes have different values than the
+same enum in libjpeg.  This represents an ABI incompatibility, and it caused
+problems with rare applications that took specific action based on a particular
+error value.  The fix was to include the new error constants conditionally
+based on whether libjpeg v7 or v8 emulation was enabled.
 
-[3] Despite the above, the fast integer forward DCT still degrades somewhat for
-JPEG qualities greater than 95, so TurboJPEG/OSS will now automatically use the
-slow integer forward DCT when generating JPEG images of quality 96 or greater.
-This reduces compression performance by as much as 15% for these high-quality
-images but is necessary to ensure that the images are perceptually lossless.
-It also ensures that the library can avoid the performance pitfall created by
-[2].
+[3] Fixed an issue whereby Windows applications that used libjpeg-turbo would
+fail to compile if the Windows system headers were included before jpeglib.h.
+This issue was caused by a conflict in the definition of the INT32 type.
 
-[4] Fixed visual artifacts in grayscale JPEG compression caused by a typo in
-the RGB-to-chrominance lookup tables.
+[4] Fixed 32-bit supplementary package for amd64 Debian systems, which was
+broken by enhancements to the packaging system in 1.1.
 
-[5] libjpeg-turbo's accelerated Huffman decoder previously ignored unexpected
+[5] Fixed out-of-bounds read in SSE2 SIMD code that occurred when decompressing
+a JPEG image to a bitmap buffer whose size was not a multiple of 16 bytes.
+This was more of an annoyance than an actual bug, since it did not cause any
+actual run-time problems, but the issue showed up when running libjpeg-turbo in
+valgrind.  See http://crbug.com/72399 for more information.
+
+
+1.1.1
+=====
+
+[1] Fixed a 1-pixel error in row 0, column 21 of the luminance plane generated
+by tjEncodeYUV().
+
+[2] libjpeg-turbo's accelerated Huffman decoder previously ignored unexpected
 markers found in the middle of the JPEG data stream during decompression.  It
 will now hand off decoding of a particular block to the unaccelerated Huffman
 decoder if an unexpected marker is found, so that the unaccelerated Huffman
 decoder can generate an appropriate warning.
 
-[6] Older versions of MinGW64 prefixed symbol names with underscores by
+[3] Older versions of MinGW64 prefixed symbol names with underscores by
 default, which differed from the behavior of 64-bit Visual C++.  MinGW64 1.0
 has adopted the behavior of 64-bit Visual C++ as the default, so to accommodate
 this, the libjpeg-turbo SIMD function names are no longer prefixed with an
@@ -34,22 +48,88 @@
 libjpeg-turbo with older versions of MinGW64, you will now have to add
 -fno-leading-underscore to the CFLAGS.
 
+[4] Fixed a regression bug in the NSIS script that caused the Windows installer
+build to fail when using the Visual Studio IDE.
+
+[5] Fixed a bug in jpeg_read_coefficients() whereby it would not initialize
+cinfo->image_width and cinfo->image_height if libjpeg v7 or v8 emulation was
+enabled.  This specifically caused the jpegoptim program to fail if it was
+linked against a version of libjpeg-turbo that was built with libjpeg v7 or v8
+emulation.
+
 [6] Eliminated excessive I/O overhead that occurred when reading BMP files in
 cjpeg.
 
-[7] Eliminated errors in the output of cjpeg and jpegtran on Windows that
-occurred when the application was invoked using I/O redirection
-(cjpeg <inputfile >output.jpg).
+[7] Eliminated errors in the output of cjpeg on Windows that occurred when the
+application was invoked using I/O redirection (cjpeg <inputfile >output.jpg).
 
-[8] Fixed an issue whereby Windows applications that used libjpeg-turbo would
-fail to compile if the Windows system headers were included before jpeglib.h.
-This issue was caused by a conflict in the definition of the INT32 type.
 
-[9] Fixed out-of-bounds read in SSE2 SIMD code that occurred when decompressing
-a JPEG image to a bitmap buffer whose size was not a multiple of 16 bytes.
-This was more of an annoyance than an actual bug, since it did not cause any
-actual run-time problems, but the issue showed up when running libjpeg-turbo in
-valgrind.  See http://crbug.com/72399 for more information.
+1.1.0
+=====
+
+[1] The algorithm used by the SIMD quantization function cannot produce correct
+results when the JPEG quality is >= 98 and the fast integer forward DCT is
+used.  Thus, the non-SIMD quantization function is now used for those cases,
+and libjpeg-turbo should now produce identical output to libjpeg v6b in all
+cases.
+
+[2] Despite the above, the fast integer forward DCT still degrades somewhat for
+JPEG qualities greater than 95, so TurboJPEG/OSS will now automatically use the
+slow integer forward DCT when generating JPEG images of quality 96 or greater.
+This reduces compression performance by as much as 15% for these high-quality
+images but is necessary to ensure that the images are perceptually lossless.
+It also ensures that the library can avoid the performance pitfall created by
+[1].
+
+[3] Ported jpgtest.cxx to pure C to avoid the need for a C++ compiler.
+
+[4] Fixed visual artifacts in grayscale JPEG compression caused by a typo in
+the RGB-to-luminance lookup tables.
+
+[5] The Windows distribution packages now include the libjpeg run-time programs
+(cjpeg, etc.)
+
+[6] All packages now include jpgtest.
+
+[7] The TurboJPEG dynamic library now uses versioned symbols.
+
+[8] Added two new TurboJPEG API functions, tjEncodeYUV() and
+tjDecompressToYUV(), to replace the somewhat hackish TJ_YUV flag.
+
+
+1.0.90 (1.1 beta1)
+==================
+
+[1] Added emulation of the libjpeg v7 and v8 APIs and ABIs.  See
+README-turbo.txt for more details.  This feature was sponsored by CamTrace SAS.
+
+[2] Created a new CMake-based build system for the Visual C++ and MinGW builds.
+
+[3] Grayscale bitmaps can now be compressed from/decompressed to using the
+TurboJPEG API.
+
+[4] jpgtest can now be used to test decompression performance with existing
+JPEG images.
+
+[5] If the default install prefix (/opt/libjpeg-turbo) is used, then
+'make install' now creates /opt/libjpeg-turbo/lib32 and
+/opt/libjpeg-turbo/lib64 sym links to duplicate the behavior of the binary
+packages.
+
+[6] All symbols in the libjpeg-turbo dynamic library are now versioned, even
+when the library is built with libjpeg v6b emulation.
+
+[7] Added arithmetic encoding and decoding support (can be disabled with
+configure or CMake options)
+
+[8] Added a TJ_YUV flag to the TurboJPEG API, which causes both the compressor
+and decompressor to output planar YUV images.
+
+[9] Added an extended version of tjDecompressHeader() to the TurboJPEG API,
+which allows the caller to determine the type of subsampling used in a JPEG
+image.
+
+[10] Added further protections against invalid Huffman codes.
 
 
 1.0.1
@@ -59,7 +139,7 @@
 from a corrupt JPEG image.)  Previously, these would cause libjpeg-turbo to
 crash under certain circumstances.
 
-[2] Fixed typo in SIMD dispatch routines which was causing 4:2:2 upsampling to
+[2] Fixed typo in SIMD dispatch routines that was causing 4:2:2 upsampling to
 be used instead of 4:2:0 when decompressing JPEG images using SSE2 code.
 
 [3] configure script will now automatically determine whether the
@@ -80,7 +160,7 @@
 [3] The Unix/Linux distribution packages now include the libjpeg run-time
 programs (cjpeg, etc.) and man pages.
 
-[4] Created a 32-bit supplementary package for amd64 Debian systems which
+[4] Created a 32-bit supplementary package for amd64 Debian systems, which
 contains just the 32-bit libjpeg-turbo libraries.
 
 [5] Moved the libraries from */lib32 to */lib in the i386 Debian package.
diff --git a/Makefile.am b/Makefile.am
index e24e779..005f040 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,11 +1,11 @@
 lib_LTLIBRARIES = libjpeg.la libturbojpeg.la
-libjpeg_la_LDFLAGS = -version-number 62:0:0 -no-undefined
+libjpeg_la_LDFLAGS = -version-info ${SO_MAJOR_VERSION}:${SO_MINOR_VERSION} -no-undefined
 libturbojpeg_la_LDFLAGS = -avoid-version -no-undefined
 include_HEADERS = jerror.h jmorecfg.h jpeglib.h turbojpeg.h
 nodist_include_HEADERS = jconfig.h
 
 HDRS = jchuff.h jdct.h jdhuff.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
-	jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h
+	jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h jpegcomp.h
 
 libjpeg_la_SOURCES = $(HDRS) jcapimin.c jcapistd.c jccoefct.c jccolor.c \
 	jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
@@ -16,12 +16,31 @@
 	jfdctflt.c jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c \
 	jidctred.c jquant1.c jquant2.c jutils.c jmemmgr.c jmemnobs.c
 
+if WITH_ARITH
+
+libjpeg_la_SOURCES += jaricom.c
+
+endif
+
+if WITH_ARITH_ENC
+
+libjpeg_la_SOURCES += jcarith.c
+
+endif
+
+if WITH_ARITH_DEC
+
+libjpeg_la_SOURCES += jdarith.c
+
+endif
+
 libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h \
 	turbojpeg-mapfile
 
 if VERSION_SCRIPT
 
 libturbojpeg_la_LDFLAGS += $(VERSION_SCRIPT_FLAG)$(srcdir)/turbojpeg-mapfile
+libjpeg_la_LDFLAGS += $(VERSION_SCRIPT_FLAG)libjpeg.map
 
 endif
 
@@ -39,12 +58,12 @@
 
 TSTHDRS = rrutil.h rrtimer.h
 
-bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom
-noinst_PROGRAMS = jpgtest jpegut
+bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom jpgtest
+noinst_PROGRAMS = jpegut
 
-jpgtest_SOURCES = $(TSTHDRS) jpgtest.cxx bmp.h bmp.c
+jpgtest_SOURCES = $(TSTHDRS) jpgtest.c bmp.h bmp.c
 
-jpgtest_LDADD = libturbojpeg.la
+jpgtest_LDADD = libturbojpeg.la -lm
 
 jpegut_SOURCES = $(TSTHDRS) jpegut.c bmp.h bmp.c
 
@@ -81,133 +100,164 @@
 
 dist_man1_MANS = cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
 
-DOCS= README install.doc usage.doc wizard.doc example.c libjpeg.doc \
-	structure.doc coderules.doc filelist.doc jconfig.doc change.log \
+DOCS= README install.txt usage.txt wizard.txt example.c libjpeg.txt \
+	structure.txt coderules.txt filelist.txt jconfig.txt change.log \
 	README-turbo.txt rdrle.c wrrle.c LICENSE.txt LGPL.txt BUILDING.txt \
 	ChangeLog.txt
 
 TESTFILES= testorig.jpg testorig.ppm testimg.bmp testimgflt.jpg \
 	testimgfst.jpg testimgint.jpg testimgp.jpg testimgflt.ppm testimgfst.ppm \
-	testimgint.ppm testimgflt-nosimd.jpg testimgfst100.jpg
+	testimgint.ppm testimgflt-nosimd.jpg testimgcrop.jpg testimgari.jpg \
+	testimgari.ppm testimgfst100.jpg
 
-EXTRA_DIST = win release $(DOCS) $(TESTFILES)
+EXTRA_DIST = win release $(DOCS) $(TESTFILES) CMakeLists.txt \
+	sharedlib/CMakeLists.txt cmakescripts libjpeg.map.in
 
 dist-hook:
 	rm -rf `find $(distdir) -name .svn`
 
 
+test: testclean all
+	./jpegut
+	./jpegut -yuv
+	./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testorig.ppm
+	cmp $(srcdir)/testimgint.jpg testoutint.jpg
+	./cjpeg -dct fast -opt -outfile testoutfst.jpg $(srcdir)/testorig.ppm
+	cmp $(srcdir)/testimgfst.jpg testoutfst.jpg
+	./cjpeg -dct fast -quality 100 -opt -outfile testoutfst100.jpg $(srcdir)/testorig.ppm
+	cmp $(srcdir)/testimgfst100.jpg testoutfst100.jpg
+	./cjpeg -dct float -outfile testoutflt.jpg $(srcdir)/testorig.ppm
 if WITH_SIMD
-
-test: testclean all
-	./jpegut
-	./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct fast -opt -outfile testoutfst.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct fast -quality 100 -opt -outfile testoutfst100.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct float -outfile testoutflt.jpg $(srcdir)/testorig.ppm
-	cmp $(srcdir)/testimgint.jpg testoutint.jpg
-	cmp $(srcdir)/testimgfst.jpg testoutfst.jpg
-	cmp $(srcdir)/testimgfst100.jpg testoutfst100.jpg
 	cmp $(srcdir)/testimgflt.jpg testoutflt.jpg
-	./djpeg -dct int -fast -ppm -outfile testoutint.ppm $(srcdir)/testorig.jpg
-	./djpeg -dct fast -ppm -outfile testoutfst.ppm $(srcdir)/testorig.jpg
-	./djpeg -dct float -ppm -outfile testoutflt.ppm $(srcdir)/testorig.jpg
-	cmp $(srcdir)/testimgint.ppm testoutint.ppm
-	cmp $(srcdir)/testimgfst.ppm testoutfst.ppm
-	cmp $(srcdir)/testimgflt.ppm testoutflt.ppm
-	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
-	cmp $(srcdir)/testimg.bmp testout.bmp
-	./cjpeg -dct int -progressive -outfile testoutp.jpg $(srcdir)/testorig.ppm
-	cmp $(srcdir)/testimgp.jpg testoutp.jpg
-	./jpegtran -outfile testoutt.jpg testoutp.jpg
-	cmp $(srcdir)/testimgint.jpg testoutt.jpg
-
 else
-
-test: testclean all
-	./jpegut
-	./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct fast -opt -outfile testoutfst.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct fast -quality 100 -opt -outfile testoutfst100.jpg $(srcdir)/testorig.ppm
-	./cjpeg -dct float -outfile testoutflt.jpg $(srcdir)/testorig.ppm
-	cmp $(srcdir)/testimgint.jpg testoutint.jpg
-	cmp $(srcdir)/testimgfst.jpg testoutfst.jpg
-	cmp $(srcdir)/testimgfst100.jpg testoutfst100.jpg
 	cmp $(srcdir)/testimgflt-nosimd.jpg testoutflt.jpg
+endif
 	./djpeg -dct int -fast -ppm -outfile testoutint.ppm $(srcdir)/testorig.jpg
-	./djpeg -dct fast -ppm -outfile testoutfst.ppm $(srcdir)/testorig.jpg
-	./djpeg -dct float -ppm -outfile testoutflt.ppm $(srcdir)/testorig.jpg
 	cmp $(srcdir)/testimgint.ppm testoutint.ppm
+	./djpeg -dct fast -ppm -outfile testoutfst.ppm $(srcdir)/testorig.jpg
 	cmp $(srcdir)/testimgfst.ppm testoutfst.ppm
+	./djpeg -dct float -ppm -outfile testoutflt.ppm $(srcdir)/testorig.jpg
+if WITH_SIMD
+	cmp $(srcdir)/testimgflt.ppm testoutflt.ppm
+else
 	cmp $(srcdir)/testorig.ppm testoutflt.ppm
+endif
 	./djpeg -dct int -bmp -colors 256 -outfile testout.bmp  $(srcdir)/testorig.jpg
 	cmp $(srcdir)/testimg.bmp testout.bmp
+if WITH_ARITH_ENC
+	./cjpeg -dct int -arithmetic -outfile testoutari.jpg $(srcdir)/testorig.ppm
+	cmp $(srcdir)/testimgari.jpg testoutari.jpg
+	./jpegtran -arithmetic -outfile testouta.jpg $(srcdir)/testimgint.jpg
+	cmp $(srcdir)/testimgari.jpg testouta.jpg
+endif
+if WITH_ARITH_DEC
+	./djpeg -dct int -fast -ppm -outfile testoutari.ppm $(srcdir)/testimgari.jpg
+	cmp $(srcdir)/testimgari.ppm testoutari.ppm
+	./jpegtran -outfile testouta.jpg $(srcdir)/testimgari.jpg
+	cmp $(srcdir)/testimgint.jpg testouta.jpg
+endif
 	./cjpeg -dct int -progressive -outfile testoutp.jpg $(srcdir)/testorig.ppm
 	cmp $(srcdir)/testimgp.jpg testoutp.jpg
 	./jpegtran -outfile testoutt.jpg testoutp.jpg
 	cmp $(srcdir)/testimgint.jpg testoutt.jpg
+	./jpegtran -crop 120x90+20+50 -transpose -perfect -outfile testoutcrop.jpg $(srcdir)/testorig.jpg
+	cmp $(srcdir)/testimgcrop.jpg testoutcrop.jpg
 
-endif
 
 testclean:
 	rm -f testout*
 	rm -f *_GRAYQ[0-9]*.bmp
 	rm -f *_GRAYQ[0-9]*.ppm
 	rm -f *_GRAYQ[0-9]*.jpg
+	rm -f *_GRAY.yuv
 	rm -f *_420Q[0-9]*.bmp
 	rm -f *_420Q[0-9]*.ppm
 	rm -f *_420Q[0-9]*.jpg
+	rm -f *_420.yuv
 	rm -f *_422Q[0-9]*.bmp
 	rm -f *_422Q[0-9]*.ppm
 	rm -f *_422Q[0-9]*.jpg
+	rm -f *_422.yuv
 	rm -f *_444Q[0-9]*.bmp
 	rm -f *_444Q[0-9]*.ppm
 	rm -f *_444Q[0-9]*.jpg
+	rm -f *_444.yuv
+
+if X86_64
+
+install-exec-hook:
+	__PREFIX=`echo ${prefix} | sed -e 's@\/*$$@@'`;  \
+	if [ "$$__PREFIX" = "/opt/libjpeg-turbo" ]; then  \
+		cd $(DESTDIR)/${prefix};  \
+		if [ -d lib -a ! -d lib64 -a ! -h lib64 ]; then  \
+			$(LN_S) lib lib64;  \
+		fi  \
+	fi
+
+else
+
+install-exec-hook:
+	__PREFIX=`echo ${prefix} | sed -e 's@\/*$$@@'`;  \
+	if [ "$$__PREFIX" = "/opt/libjpeg-turbo" ]; then  \
+		cd $(DESTDIR)/${prefix};  \
+		if [ -d lib -a ! -d lib32 -a ! -h lib32 ]; then  \
+			$(LN_S) lib lib32;  \
+		fi  \
+	fi
+
+endif
 
 rpm: all
-	sh $(srcdir)/release/makerpm ${PACKAGE_NAME} ${VERSION} ${BUILD} \
-		${RPMARCH} ${srcdir}
+	TMPDIR=`mktemp -d /tmp/${PACKAGE_NAME}-build.XXXXXX`; \
+	mkdir -p $$TMPDIR/RPMS; \
+	ln -fs `pwd` $$TMPDIR/BUILD; \
+	rm -f ${PACKAGE_NAME}-${VERSION}.${RPMARCH}.rpm; \
+	rpmbuild -bb --define "_blddir $$TMPDIR/buildroot"  \
+		--define "_topdir $$TMPDIR" --define "_srcdir ${srcdir}" \
+		--target ${RPMARCH} pkgscripts/libjpeg-turbo.spec; \
+	cp $$TMPDIR/RPMS/${RPMARCH}/${PACKAGE_NAME}-${VERSION}-${BUILD}.${RPMARCH}.rpm \
+		${PACKAGE_NAME}-${VERSION}.${RPMARCH}.rpm; \
+	rm -rf $$TMPDIR
 
 srpm: dist-gzip
-	sh $(srcdir)/release/makesrpm ${PACKAGE_NAME} ${VERSION} ${BUILD} ${srcdir}
+	TMPDIR=`mktemp -d /tmp/${PACKAGE_NAME}-build.XXXXXX`; \
+	mkdir -p $$TMPDIR/RPMS; \
+	mkdir -p $$TMPDIR/SRPMS; \
+	mkdir -p $$TMPDIR/BUILD; \
+	mkdir -p $$TMPDIR/SOURCES; \
+	mkdir -p $$TMPDIR/SPECS; \
+	rm -f ${PACKAGE_NAME}-${VERSION}.src.rpm; \
+	cp ${PACKAGE_NAME}-${VERSION}.tar.gz $$TMPDIR/SOURCES; \
+	cat pkgscripts/libjpeg-turbo.spec | sed s/%{_blddir}/%{_tmppath}/g \
+		| sed s@%{_srcdir}/@@g | sed s/#--\>//g \
+		> $$TMPDIR/SPECS/libjpeg-turbo.spec; \
+	rpmbuild -bs --define "_topdir $$TMPDIR" $$TMPDIR/SPECS/libjpeg-turbo.spec; \
+	cp $$TMPDIR/SRPMS/${PACKAGE_NAME}-${VERSION}-${BUILD}.src.rpm \
+		${PACKAGE_NAME}-${VERSION}.src.rpm; \
+	rm -rf $$TMPDIR
 
 deb: all
-	sh $(srcdir)/release/makedpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
-		${DEBARCH} ${srcdir}
+	sh pkgscripts/makedpkg
 
 if X86_64
 
 udmg: all
-	sh $(srcdir)/release/makemacpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
-		${srcdir} universal
+	sh pkgscripts/makemacpkg universal ${BUILDDIR32}
 
 endif
 
 dmg: all
-	sh $(srcdir)/release/makemacpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} ${srcdir}
+	sh pkgscripts/makemacpkg
 
 if X86_64
 
-sunpkg: all
-	sh $(srcdir)/release/makesunpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
-		${DEBARCH} ${srcdir} $(CC) $(CXX) combined
-
-nsi: all
-	makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo-gcc64 \
-		-DWLIBDIR=.libs -DWSRCDIR=$(srcdir) -DWBLDDIR=. -DWHDRDIR=. -DWIN64 \
-		-DPLATFORM="GCC 64-bit" -DGCC $(srcdir)/release/libjpeg-turbo.nsi
-
-else
-
-sunpkg: all
-	sh $(srcdir)/release/makesunpkg ${PACKAGE_NAME} ${VERSION} ${BUILD} \
-		${DEBARCH} ${srcdir} $(CC) $(CXX)
-
-nsi: all
-	makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo-gcc \
-		-DWLIBDIR=.libs -DWSRCDIR=$(srcdir) -DWBLDDIR=. -DWHDRDIR=. \
-		-DPLATFORM="GCC" -DGCC $(srcdir)/release/libjpeg-turbo.nsi
+csunpkg: all
+	sh pkgscripts/makesunpkg combined ${BUILDDIR32}
 
 endif
 
+sunpkg: all
+	sh pkgscripts/makesunpkg
+
 cygwinpkg: all
-	sh $(srcdir)/release/makecygwinpkg ${PACKAGE_NAME} ${VERSION} ${srcdir}
+	sh pkgscripts/makecygwinpkg
diff --git a/README b/README
index 22e89b0..0e9b429 100644
--- a/README
+++ b/README
@@ -1,29 +1,21 @@
-libjpeg-turbo note:  This is the legacy document from the original libjpeg v6b
-release, which is included for reference.  The Internet addresses given below
-are likely non-functional.  For more information about the libjpeg project,
-please see http://www.ijg.org.  For more information about libjpeg-turbo,
-please see http://libjpeg-turbo.virtualgl.org.
+libjpeg-turbo note:  This file contains portions of the libjpeg v6b and v8
+README files, with additional wordsmithing by The libjpeg-turbo Project.
+It is included only for reference, as some parts of it may not apply to
+libjpeg-turbo.  Please see README-turbo.txt for information specific to
+libjpeg-turbo.
 
 
 The Independent JPEG Group's JPEG software
 ==========================================
 
-README for release 6b of 27-Mar-1998
-====================================
+This distribution contains a release of the Independent JPEG Group's free JPEG
+software.  You are welcome to redistribute this software and to use it for any
+purpose, subject to the conditions under LEGAL ISSUES, below.
 
-This distribution contains the sixth public release of the Independent JPEG
-Group's free JPEG software.  You are welcome to redistribute this software and
-to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
-
-Serious users of this software (particularly those incorporating it into
-larger programs) should contact IJG at jpeg-info@uunet.uu.net to be added to
-our electronic mailing list.  Mailing list members are notified of updates
-and have a chance to participate in technical discussions, etc.
-
-This software is the work of Tom Lane, Philip Gladstone, Jim Boucher,
-Lee Crocker, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,
-Guido Vollbeding, Ge' Weijers, and other members of the Independent JPEG
-Group.
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
+and other members of the Independent JPEG Group.
 
 IJG is not affiliated with the official ISO JPEG standards committee.
 
@@ -37,27 +29,26 @@
 LEGAL ISSUES        Copyright, lack of warranty, terms of distribution.
 REFERENCES          Where to learn more about JPEG.
 ARCHIVE LOCATIONS   Where to find newer versions of this software.
-RELATED SOFTWARE    Other stuff you should get.
 FILE FORMAT WARS    Software *not* to get.
 TO DO               Plans for future IJG releases.
 
 Other documentation files in the distribution are:
 
 User documentation:
-  install.doc       How to configure and install the IJG software.
-  usage.doc         Usage instructions for cjpeg, djpeg, jpegtran,
+  install.txt       How to configure and install the IJG software.
+  usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,
                     rdjpgcom, and wrjpgcom.
-  *.1               Unix-style man pages for programs (same info as usage.doc).
-  wizard.doc        Advanced usage instructions for JPEG wizards only.
+  *.1               Unix-style man pages for programs (same info as usage.txt).
+  wizard.txt        Advanced usage instructions for JPEG wizards only.
   change.log        Version-to-version change highlights.
 Programmer and internal documentation:
-  libjpeg.doc       How to use the JPEG library in your own programs.
+  libjpeg.txt       How to use the JPEG library in your own programs.
   example.c         Sample code for calling the JPEG library.
-  structure.doc     Overview of the JPEG library's internal structure.
-  filelist.doc      Road map of IJG files.
-  coderules.doc     Coding style rules --- please read if you contribute code.
+  structure.txt     Overview of the JPEG library's internal structure.
+  filelist.txt      Road map of IJG files.
+  coderules.txt     Coding style rules --- please read if you contribute code.
 
-Please read at least the files install.doc and usage.doc.  Useful information
+Please read at least the files install.txt and usage.txt.  Some information
 can also be found in the JPEG FAQ (Frequently Asked Questions) article.  See
 ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
 
@@ -69,24 +60,27 @@
 OVERVIEW
 ========
 
-This package contains C software to implement JPEG image compression and
-decompression.  JPEG (pronounced "jay-peg") is a standardized compression
-method for full-color and gray-scale images.  JPEG is intended for compressing
-"real-world" scenes; line drawings, cartoons and other non-realistic images
-are not its strong suit.  JPEG is lossy, meaning that the output image is not
-exactly identical to the input image.  Hence you must not use JPEG if you
-have to have identical output bits.  However, on typical photographic images,
-very good compression levels can be obtained with no visible change, and
-remarkably high compression levels are possible if you can tolerate a
-low-quality image.  For more details, see the references, or just experiment
-with various compression settings.
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding.  JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images.  JPEG's strong suit is compressing
+photographic images or other types of images that have smooth color and
+brightness transitions between neighboring pixels.  Images with sharp lines or
+other abrupt features may not compress well with JPEG, and a higher JPEG
+quality may have to be used to avoid visible compression artifacts with such
+images.
+
+JPEG is lossy, meaning that the output pixels are not necessarily identical to
+the input pixels.  However, on photographic content and other "smooth" images,
+very good compression ratios can be obtained with no visible compression
+artifacts, and extremely high compression ratios are possible if you are
+willing to sacrifice image quality (by reducing the "quality" setting in the
+compressor.)
 
 This software implements JPEG baseline, extended-sequential, and progressive
 compression processes.  Provision is made for supporting all variants of these
 processes, although some uncommon parameter settings aren't implemented yet.
-For legal reasons, we are not distributing code for the arithmetic-coding
-variants of JPEG; see LEGAL ISSUES.  We have made no provision for supporting
-the hierarchical or lossless processes defined in the standard.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
 
 We provide a set of library routines for reading and writing JPEG image files,
 plus two sample applications "cjpeg" and "djpeg", which use the library to
@@ -98,10 +92,11 @@
 for example, the color quantization modules are not strictly part of JPEG
 decoding, but they are essential for output to colormapped file formats or
 colormapped displays.  These extra functions can be compiled out of the
-library if not required for a particular application.  We have also included
-"jpegtran", a utility for lossless transcoding between different JPEG
-processes, and "rdjpgcom" and "wrjpgcom", two simple applications for
-inserting and extracting textual comments in JFIF files.
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
 
 The emphasis in designing this software has been on achieving portability and
 flexibility, while also making it fast enough to be useful.  In particular,
@@ -134,7 +129,7 @@
 fitness for a particular purpose.  This software is provided "AS IS", and you,
 its user, assume the entire risk as to its quality and accuracy.
 
-This software is copyright (C) 1991-1998, Thomas G. Lane.
+This software is copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding.
 All Rights Reserved except as specified below.
 
 Permission is hereby granted to use, copy, modify, and distribute this
@@ -177,17 +172,8 @@
 The Unix configuration script "configure" was produced with GNU Autoconf.
 It is copyright by the Free Software Foundation but is freely distributable.
 The same holds for its supporting scripts (config.guess, config.sub,
-ltconfig, ltmain.sh).  Another support script, install-sh, is copyright
-by M.I.T. but is also freely distributable.
-
-It appears that the arithmetic coding option of the JPEG spec is covered by
-patents owned by IBM, AT&T, and Mitsubishi.  Hence arithmetic coding cannot
-legally be used without obtaining one or more licenses.  For this reason,
-support for arithmetic coding has been removed from the free JPEG software.
-(Since arithmetic coding provides only a marginal gain over the unpatented
-Huffman mode, it is unlikely that very many implementations will support it.)
-So far as we are aware, there are no patent restrictions on the remaining
-code.
+ltmain.sh).  Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
 
 The IJG distribution formerly included code to read and write GIF files.
 To avoid entanglement with the Unisys LZW patent, GIF reading support has
@@ -205,7 +191,7 @@
 REFERENCES
 ==========
 
-We highly recommend reading one or more of these references before trying to
+We recommend reading one or more of these references before trying to
 understand the innards of the JPEG software.
 
 The best short technical introduction to the JPEG compression algorithm is
@@ -214,7 +200,7 @@
 (Adjacent articles in that issue discuss MPEG motion picture compression,
 applications of JPEG, and related topics.)  If you don't have the CACM issue
 handy, a PostScript file containing a revised version of Wallace's article is
-available at ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz.  The file (actually
+available at http://www.ijg.org/files/wallace.ps.gz.  The file (actually
 a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
 omits the sample images that appeared in CACM, but it includes corrections
 and some added material.  Note: the Wallace article is copyright ACM and IEEE,
@@ -229,82 +215,53 @@
 sample code is far from industrial-strength, but when you are ready to look
 at a full implementation, you've got one here...
 
-The best full description of JPEG is the textbook "JPEG Still Image Data
-Compression Standard" by William B. Pennebaker and Joan L. Mitchell, published
-by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.  Price US$59.95, 638 pp.
-The book includes the complete text of the ISO JPEG standards (DIS 10918-1
-and draft DIS 10918-2).  This is by far the most complete exposition of JPEG
-in existence, and we highly recommend it.
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
 
-The JPEG standard itself is not available electronically; you must order a
-paper copy through ISO or ITU.  (Unless you feel a need to own a certified
-official copy, we recommend buying the Pennebaker and Mitchell book instead;
-it's much cheaper and includes a great deal of useful explanatory material.)
-In the USA, copies of the standard may be ordered from ANSI Sales at (212)
-642-4900, or from Global Engineering Documents at (800) 854-7179.  (ANSI
-doesn't take credit card orders, but Global does.)  It's not cheap: as of
-1992, ANSI was charging $95 for Part 1 and $47 for Part 2, plus 7%
-shipping/handling.  The standard is divided into two parts, Part 1 being the
-actual specification, while Part 2 covers compliance testing methods.  Part 1
-is titled "Digital Compression and Coding of Continuous-tone Still Images,
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods.  Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
 Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
 10918-1, ITU-T T.81.  Part 2 is titled "Digital Compression and Coding of
 Continuous-tone Still Images, Part 2: Compliance testing" and has document
 numbers ISO/IEC IS 10918-2, ITU-T T.83.
 
-Some extensions to the original JPEG standard are defined in JPEG Part 3,
-a newer ISO standard numbered ISO/IEC IS 10918-3 and ITU-T T.84.  IJG
-currently does not support any Part 3 extensions.
-
 The JPEG standard does not specify all details of an interchangeable file
 format.  For the omitted details we follow the "JFIF" conventions, revision
-1.02.  A copy of the JFIF spec is available from:
-	Literature Department
-	C-Cube Microsystems, Inc.
-	1778 McCarthy Blvd.
-	Milpitas, CA 95035
-	phone (408) 944-6300,  fax (408) 944-6314
-A PostScript version of this document is available by FTP at
-ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz.  There is also a plain text
-version at ftp://ftp.uu.net/graphics/jpeg/jfif.txt.gz, but it is missing
-the figures.
+1.02.  JFIF 1.02 has been adopted as an Ecma International Technical Report
+and thus received a formal publication status.  It is available as a free
+download in PDF format from
+http://www.ecma-international.org/publications/techreports/E-TR-098.htm.
+A PostScript version of the JFIF document is available at
+http://www.ijg.org/files/jfif.ps.gz.  There is also a plain text version at
+http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures.
 
 The TIFF 6.0 file format specification can be obtained by FTP from
 ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation scheme
 found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
 IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
 Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
-(Compression tag 7).  Copies of this Note can be obtained from ftp.sgi.com or
-from ftp://ftp.uu.net/graphics/jpeg/.  It is expected that the next revision
+(Compression tag 7).  Copies of this Note can be obtained from
+http://www.ijg.org/files/.  It is expected that the next revision
 of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
 Although IJG's own code does not support TIFF/JPEG, the free libtiff library
-uses our library to implement TIFF/JPEG per the Note.  libtiff is available
-from ftp://ftp.sgi.com/graphics/tiff/.
+uses our library to implement TIFF/JPEG per the Note.
 
 
 ARCHIVE LOCATIONS
 =================
 
-The "official" archive site for this software is ftp.uu.net (Internet
-address 192.48.96.9).  The most recent released version can always be found
-there in directory graphics/jpeg.  This particular version will be archived
-as ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6b.tar.gz.  If you don't have
-direct Internet access, UUNET's archives are also available via UUCP; contact
-help@uunet.uu.net for information on retrieving files that way.
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files".  This particular version will be archived as
+http://www.ijg.org/files/jpegsrc.v8d.tar.gz, and in Windows-compatible
+"zip" archive format as http://www.ijg.org/files/jpegsr8d.zip.
 
-Numerous Internet sites maintain copies of the UUNET files.  However, only
-ftp.uu.net is guaranteed to have the latest official version.
-
-You can also obtain this software in DOS-compatible "zip" archive format from
-the SimTel archives (ftp://ftp.simtel.net/pub/simtelnet/msdos/graphics/), or
-on CompuServe in the Graphics Support forum (GO CIS:GRAPHSUP), library 12
-"JPEG Tools".  Again, these versions may sometimes lag behind the ftp.uu.net
-release.
-
-The JPEG FAQ (Frequently Asked Questions) article is a useful source of
-general information about JPEG.  It is updated constantly and therefore is
-not included in this distribution.  The FAQ is posted every two weeks to
-Usenet newsgroups comp.graphics.misc, news.answers, and other groups.
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
 It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
 and other news.answers archive sites, including the official news.answers
 archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
@@ -314,79 +271,20 @@
 	send usenet/news.answers/jpeg-faq/part2
 
 
-RELATED SOFTWARE
-================
-
-Numerous viewing and image manipulation programs now support JPEG.  (Quite a
-few of them use this library to do so.)  The JPEG FAQ described above lists
-some of the more popular free and shareware viewers, and tells where to
-obtain them on Internet.
-
-If you are on a Unix machine, we highly recommend Jef Poskanzer's free
-PBMPLUS software, which provides many useful operations on PPM-format image
-files.  In particular, it can convert PPM images to and from a wide range of
-other formats, thus making cjpeg/djpeg considerably more useful.  The latest
-version is distributed by the NetPBM group, and is available from numerous
-sites, notably ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/.
-Unfortunately PBMPLUS/NETPBM is not nearly as portable as the IJG software is;
-you are likely to have difficulty making it work on any non-Unix machine.
-
-A different free JPEG implementation, written by the PVRG group at Stanford,
-is available from ftp://havefun.stanford.edu/pub/jpeg/.  This program
-is designed for research and experimentation rather than production use;
-it is slower, harder to use, and less portable than the IJG code, but it
-is easier to read and modify.  Also, the PVRG code supports lossless JPEG,
-which we do not.  (On the other hand, it doesn't do progressive JPEG.)
-
-
 FILE FORMAT WARS
 ================
 
-Some JPEG programs produce files that are not compatible with our library.
-The root of the problem is that the ISO JPEG committee failed to specify a
-concrete file format.  Some vendors "filled in the blanks" on their own,
-creating proprietary formats that no one else could read.  (For example, none
-of the early commercial JPEG implementations for the Macintosh were able to
-exchange compressed files.)
-
-The file format we have adopted is called JFIF (see REFERENCES).  This format
-has been agreed to by a number of major commercial JPEG vendors, and it has
-become the de facto standard.  JFIF is a minimal or "low end" representation.
-We recommend the use of TIFF/JPEG (TIFF revision 6.0 as modified by TIFF
-Technical Note #2) for "high end" applications that need to record a lot of
-additional data about an image.  TIFF/JPEG is fairly new and not yet widely
-supported, unfortunately.
-
-The upcoming JPEG Part 3 standard defines a file format called SPIFF.
-SPIFF is interoperable with JFIF, in the sense that most JFIF decoders should
-be able to read the most common variant of SPIFF.  SPIFF has some technical
-advantages over JFIF, but its major claim to fame is simply that it is an
-official standard rather than an informal one.  At this point it is unclear
-whether SPIFF will supersede JFIF or whether JFIF will remain the de-facto
-standard.  IJG intends to support SPIFF once the standard is frozen, but we
-have not decided whether it should become our default output format or not.
-(In any case, our decoder will remain capable of reading JFIF indefinitely.)
-
-Various proprietary file formats incorporating JPEG compression also exist.
-We have little or no sympathy for the existence of these formats.  Indeed,
+The ISO JPEG standards committee actually promotes different formats like
+"JPEG 2000" or "JPEG XR", which are incompatible with original DCT-based
+JPEG.  IJG therefore does not support these formats (see REFERENCES).  Indeed,
 one of the original reasons for developing this free software was to help
-force convergence on common, open format standards for JPEG files.  Don't
-use a proprietary file format!
+force convergence on common, interoperable format standards for JPEG files.
+Don't use an incompatible file format!
+(In any case, our decoder will remain capable of reading existing JPEG
+image files indefinitely.)
 
 
 TO DO
 =====
 
-The major thrust for v7 will probably be improvement of visual quality.
-The current method for scaling the quantization tables is known not to be
-very good at low Q values.  We also intend to investigate block boundary
-smoothing, "poor man's variable quantization", and other means of improving
-quality-vs-file-size performance without sacrificing compatibility.
-
-In future versions, we are considering supporting some of the upcoming JPEG
-Part 3 extensions --- principally, variable quantization and the SPIFF file
-format.
-
-As always, speeding things up is of great interest.
-
-Please send bug reports, offers of help, etc. to jpeg-info@uunet.uu.net.
+Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
diff --git a/README-turbo.txt b/README-turbo.txt
index f340fd6..fcfd27e 100755
--- a/README-turbo.txt
+++ b/README-turbo.txt
@@ -2,23 +2,24 @@
 **     Background
 *******************************************************************************
 
-libjpeg-turbo is a high-speed version of libjpeg for x86 and x86-64 processors
-which uses SIMD instructions (MMX, SSE2, etc.) to accelerate baseline JPEG
-compression and decompression.  libjpeg-turbo is generally 2-4x as fast
-as the unmodified version of libjpeg v6b, all else being equal.
+libjpeg-turbo is a derivative of libjpeg that uses SIMD instructions (MMX,
+SSE2, etc.) to accelerate baseline JPEG compression and decompression on x86
+and x86-64 systems.  On such systems, libjpeg-turbo is generally 2-4x as fast
+as the unmodified version of libjpeg, all else being equal.
 
 libjpeg-turbo was originally based on libjpeg/SIMD by Miyasaka Masaru, but
-the TigerVNC and VirtualGL projects made numerous enhancements to the codec,
-including improved support for Mac OS X, 64-bit support, support for 32-bit
-and big endian pixel formats, accelerated Huffman encoding/decoding, and
-various bug fixes.  The goal was to produce a fully open source codec that
-could replace the partially closed source TurboJPEG/IPP codec used by VirtualGL
-and TurboVNC.  libjpeg-turbo generally performs in the range of 80-120% of
-TurboJPEG/IPP.  It is faster in some areas but slower in others.
+the TigerVNC and VirtualGL projects made numerous enhancements to the codec in
+2009, including improved support for Mac OS X, 64-bit support, support for
+32-bit and big-endian pixel formats (RGBX, XBGR, etc.), accelerated Huffman
+encoding/decoding, and various bug fixes.  The goal was to produce a fully
+open-source codec that could replace the partially closed-source TurboJPEG/IPP
+codec used by VirtualGL and TurboVNC.  libjpeg-turbo generally achieves 80-120%
+of the performance of TurboJPEG/IPP.  It is faster in some areas but slower in
+others.
 
-It was decided to split libjpeg-turbo into a separate SDK so that other
-projects could take advantage of this technology.  The libjpeg-turbo shared
-libraries can be used as drop-in replacements for libjpeg on most systems.
+In early 2010, libjpeg-turbo spun off into its own independent project, with
+the goal of making high-speed JPEG compression/decompression technology
+available to a broader range of users and developers.
 
 
 *******************************************************************************
@@ -27,10 +28,10 @@
 
 The TurboJPEG/OSS wrapper, as well as some of the optimizations to the Huffman
 encoder (jchuff.c) and decoder (jdhuff.c), were borrowed from VirtualGL, and
-thus any distribution of libjpeg-turbo which includes those files must, as a
+thus any distribution of libjpeg-turbo that includes those files must, as a
 whole, be subject to the terms of the wxWindows Library Licence, Version 3.1.
 A copy of this license can be found in this directory under LICENSE.txt.  The
-wxWindows Library License is based on the LGPL but includes provisions which
+wxWindows Library License is based on the LGPL but includes provisions that
 allow the Library to be statically linked into proprietary libraries and
 applications without requiring the resulting binaries to be distributed under
 the terms of the LGPL.
@@ -71,36 +72,39 @@
 architecture.
 
 System administrators can also replace the libjpeg sym links in /usr/{lib} with
-links to the libjpeg dynamic library located in /opt/libjpeg-turbo/{lib}.  This
-will effectively accelerate every dynamically linked libjpeg application on the
-system.
+links to the libjpeg-turbo dynamic library located in /opt/libjpeg-turbo/{lib}.
+This will effectively accelerate every application that uses the libjpeg
+dynamic library on the system.
 
-The libjpeg-turbo SDK for Visual C++ installs jpeg62.dll into
-c:\libjpeg-turbo[64]\bin, and the PATH environment variable can be modified
-such that this directory is searched before any others that might contain
-jpeg62.dll.  However, if jpeg62.dll also exists in an application's install
-directory, then Windows will load the application's version of it first.  Thus,
-if an application ships with jpeg62.dll, then back up the application's version
-of jpeg62.dll and copy c:\libjpeg-turbo[64]\bin\jpeg62.dll into the
+The libjpeg-turbo SDK for Visual C++ installs the libjpeg-turbo DLL
+(jpeg62.dll, jpeg7.dll, or jpeg8.dll, depending on whether it was built with
+libjpeg v6b, v7, or v8 emulation) into c:\libjpeg-turbo[64]\bin, and the PATH
+environment variable can be modified such that this directory is searched
+before any others that might contain a libjpeg DLL.  However, if a libjpeg
+DLL exists in an application's install directory, then Windows will load this
+DLL first whenever the application is launched.  Thus, if an application ships
+with jpeg62.dll, jpeg7.dll, or jpeg8.dll, then back up the application's
+version of this DLL and copy c:\libjpeg-turbo[64]\bin\jpeg*.dll into the
 application's install directory to accelerate it.
 
-The version of jpeg62.dll distributed in the libjpeg-turbo SDK for Visual C++
-requires the Visual C++ 2008 C run time DLL (msvcr90.dll).  msvcr90.dll ships
-with more recent versions of Windows, but users of older Windows releases can
-obtain it from the Visual C++ 2008 Redistributable Package, which is available
-as a free download from Microsoft's web site.
+The version of the libjpeg-turbo DLL distributed in the libjpeg-turbo SDK for
+Visual C++ requires the Visual C++ 2008 C run-time DLL (msvcr90.dll).
+msvcr90.dll ships with more recent versions of Windows, but users of older
+Windows releases can obtain it from the Visual C++ 2008 Redistributable
+Package, which is available as a free download from Microsoft's web site.
 
-NOTE:  Features of libjpeg which require passing a C run time structure, such
+NOTE:  Features of libjpeg that require passing a C run-time structure, such
 as a file handle, from an application to libjpeg will probably not work with
-the version of jpeg62.dll distributed in the libjpeg-turbo SDK for Visual C++,
-unless the application is also built to use the Visual C++ 2008 C run time DLL.
-In particular, this affects jpeg_stdio_dest() and jpeg_stdio_src().
+the version of the libjpeg-turbo DLL distributed in the libjpeg-turbo SDK for
+Visual C++, unless the application is also built to use the Visual C++ 2008 C
+run-time DLL.  In particular, this affects jpeg_stdio_dest() and
+jpeg_stdio_src().
 
-Mac applications typically embed their own copies of libjpeg.62.dylib inside
+Mac applications typically embed their own copies of the libjpeg dylib inside
 the (hidden) application bundle, so it is not possible to globally replace
 libjpeg on OS X systems.  If an application uses a shared library version of
 libjpeg, then it may be possible to replace the application's version of it.
-This would generally involve copying libjpeg.62.dylib from libjpeg-turbo into
+This would generally involve copying libjpeg.*.dylib from libjpeg-turbo into
 the appropriate place in the application bundle and using install_name_tool to
 repoint the dylib to the new directory.  This requires an advanced knowledge of
 OS X and would not survive an upgrade or a re-install of the application.
@@ -113,7 +117,7 @@
 libjpeg-turbo is a drop-in replacement for the TurboJPEG/IPP SDK used by
 VirtualGL 2.1.x and TurboVNC 0.6 (and prior.)  libjpeg-turbo contains a wrapper
 library (TurboJPEG/OSS) that emulates the TurboJPEG API using libjpeg-turbo
-instead of the closed source Intel Performance Primitives.  You can replace the
+instead of the closed-source Intel Performance Primitives.  You can replace the
 TurboJPEG/IPP package on Linux systems with the libjpeg-turbo package in order
 to make existing releases of VirtualGL 2.1.x and TurboVNC 0.x use the new codec
 at run time.  Note that the 64-bit libjpeg-turbo packages contain only 64-bit
@@ -124,7 +128,7 @@
 You can also build the VirtualGL 2.1.x and TurboVNC 0.6 source code with
 the libjpeg-turbo SDK instead of TurboJPEG/IPP.  It should work identically.
 libjpeg-turbo also includes static library versions of TurboJPEG/OSS, which
-are used to build TurboVNC 1.0 and later.
+are used to build VirtualGL 2.2 and TurboVNC 1.0 and later.
 
 ========================================
 Using libjpeg-turbo in Your Own Programs
@@ -168,15 +172,15 @@
 To build Visual C++ applications using libjpeg-turbo, add
 c:\libjpeg-turbo[64]\include to the system or user INCLUDE environment
 variable and c:\libjpeg-turbo[64]\lib to the system or user LIB environment
-variable, and then link against either jpeg.lib (to use jpeg62.dll) or
-jpeg-static.lib (to use the static version of libjpeg-turbo.)
+variable, and then link against either jpeg.lib (to use the DLL version of
+libjpeg-turbo) or jpeg-static.lib (to use the static version of libjpeg-turbo.)
 
 =====================
 Colorspace Extensions
 =====================
 
-libjpeg-turbo includes extensions which allow JPEG images to be compressed
-directly from (and decompressed directly to) buffers which use BGR, BGRX,
+libjpeg-turbo includes extensions that allow JPEG images to be compressed
+directly from (and decompressed directly to) buffers that use BGR, BGRX,
 RGBX, XBGR, and XRGB pixel ordering.  This is implemented with six new
 colorspace constants:
 
@@ -190,7 +194,7 @@
 Setting cinfo.in_color_space (compression) or cinfo.out_color_space
 (decompression) to one of these values will cause libjpeg-turbo to read the
 red, green, and blue values from (or write them to) the appropriate position in
-the pixel when YUV conversion is performed.
+the pixel when compressing from/decompressing to an RGB buffer.
 
 Your application can check for the existence of these extensions at compile
 time with:
@@ -200,6 +204,85 @@
 At run time, attempting to use these extensions with a version of libjpeg
 that doesn't support them will result in a "Bogus input colorspace" error.
 
+=================================
+libjpeg v7 and v8 API/ABI support
+=================================
+
+With libjpeg v7 and v8, new features were added that necessitated extending the
+compression and decompression structures.  Unfortunately, due to the exposed
+nature of those structures, extending them also necessitated breaking backward
+ABI compatibility with previous libjpeg releases.  Thus, programs that are
+built to use libjpeg v7 or v8 did not work with libjpeg-turbo, since it is
+based on the libjpeg v6b code base.  Although libjpeg v7 and v8 are still not
+as widely used as v6b, enough programs (including a few Linux distros) have
+made the switch that it was desirable to provide support for the libjpeg v7/v8
+API/ABI in libjpeg-turbo.  Although libjpeg-turbo can now be configured as a
+drop-in replacement for libjpeg v7 or v8, it should be noted that not all of
+the features in libjpeg v7 and v8 are supported (see below.)
+
+By passing an argument of --with-jpeg7 or --with-jpeg8 to configure, or an
+argument of -DWITH_JPEG7=1 or -DWITH_JPEG8=1 to cmake, you can build a version
+of libjpeg-turbo that emulates the libjpeg v7 or v8 API/ABI, so that programs
+that are built against libjpeg v7 or v8 can be run with libjpeg-turbo.  The
+following section describes which libjpeg v7+ features are supported and which
+aren't.
+
+libjpeg v7 and v8 Features:
+---------------------------
+
+Fully supported:
+
+-- cjpeg: Separate quality settings for luminance and chrominance
+   Note that the libpjeg v7+ API was extended to accommodate this feature only
+   for convenience purposes.  It has always been possible to implement this
+   feature with libjpeg v6b (see rdswitch.c for an example.)
+
+-- cjpeg: 32-bit BMP support
+
+-- jpegtran: lossless cropping
+
+-- jpegtran: -perfect option
+
+-- rdjpgcom: -raw option
+
+-- rdjpgcom: locale awareness
+
+
+Fully supported when using libjpeg v7/v8 emulation:
+
+-- libjpeg: In-memory source and destination managers
+
+
+Not supported:
+
+-- libjpeg: DCT scaling in compressor
+   cinfo.scale_num and cinfo.scale_denom are silently ignored.
+   There is no technical reason why DCT scaling cannot be supported, but
+   without the SmartScale extension (see below), it would only be able to
+   down-scale using ratios of 1/2, 8/15, 4/7, 8/13, 2/3, 8/11, 4/5, and 8/9,
+   which is of limited usefulness.
+
+-- libjpeg: SmartScale
+   cinfo.block_size is silently ignored.
+   SmartScale is an extension to the JPEG format that allows for DCT block
+   sizes other than 8x8.  It would be difficult to support this feature while
+   retaining backward compatibility with libjpeg v6b.
+
+-- libjpeg: IDCT scaling extensions in decompressor
+   libjpeg-turbo still supports IDCT scaling with scaling factors of 1/2, 1/4,
+   and 1/8 (same as libjpeg v6b.)
+
+-- libjpeg: Fancy downsampling in compressor
+   cinfo.do_fancy_downsampling is silently ignored.
+   This requires the DCT scaling feature, which is not supported.
+
+-- jpegtran: Scaling
+   This requires both the DCT scaling and SmartScale features, which are not
+   supported.
+
+-- Lossless RGB JPEG files
+   This requires the SmartScale feature, which is not supported.
+
 
 *******************************************************************************
 **     Performance pitfalls
@@ -210,12 +293,13 @@
 ===============
 
 The optimized Huffman decoder in libjpeg-turbo does not handle restart markers
-in a way that makes libjpeg happy, so it is necessary to use the slow Huffman
-decoder when decompressing a JPEG image that has restart markers.  This can
-cause the decompression performance to drop by as much as 20%, but the
-performance will still be much much greater than that of libjpeg v6b.  Many
-consumer packages, such as PhotoShop, use restart markers when generating JPEG
-images, so images generated by those programs will experience this issue.
+in a way that makes the rest of the libjpeg infrastructure happy, so it is
+necessary to use the slow Huffman decoder when decompressing a JPEG image that
+has restart markers.  This can cause the decompression performance to drop by
+as much as 20%, but the performance will still be much greater than that of
+libjpeg.  Many consumer packages, such as PhotoShop, use restart markers when
+generating JPEG images, so images generated by those programs will experience
+this issue.
 
 ===============================================
 Fast Integer Forward DCT at High Quality Levels
diff --git a/bmp.h b/bmp.h
index 437d327..055b1ee 100644
--- a/bmp.h
+++ b/bmp.h
@@ -1,5 +1,6 @@
 /* Copyright (C)2004 Landmark Graphics Corporation
  * Copyright (C)2005 Sun Microsystems, Inc.
+ * Copyright (C)2011 D. R. Commander
  *
  * This library is free software and may be redistributed and/or modified under
  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -19,7 +20,7 @@
 #define __BMP_H__
 
 #define BMPPIXELFORMATS 6
-enum BMPPIXELFORMAT {BMP_RGB=0, BMP_RGBA, BMP_BGR, BMP_BGRA, BMP_ABGR, BMP_ARGB};
+enum BMPPIXELFORMAT {BMP_RGB=0, BMP_RGBX, BMP_BGR, BMP_BGRX, BMP_XBGR, BMP_XRGB};
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/cderror.h b/cderror.h
index 70435e1..e19c475 100644
--- a/cderror.h
+++ b/cderror.h
@@ -2,6 +2,7 @@
  * cderror.h
  *
  * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -45,6 +46,7 @@
 JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
 JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
 JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
+JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
 JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
 JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
 JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
diff --git a/cdjpeg.h b/cdjpeg.h
index 2b387b6..ed024ac 100644
--- a/cdjpeg.h
+++ b/cdjpeg.h
@@ -104,6 +104,7 @@
 #define jinit_write_targa	jIWrTarga
 #define read_quant_tables	RdQTables
 #define read_scan_script	RdScnScript
+#define set_quality_ratings     SetQRates
 #define set_quant_slots		SetQSlots
 #define set_sample_factors	SetSFacts
 #define read_color_map		RdCMap
@@ -131,8 +132,10 @@
 /* cjpeg support routines (in rdswitch.c) */
 
 EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,
-				    int scale_factor, boolean force_baseline));
+				       boolean force_baseline));
 EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));
+EXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg,
+					 boolean force_baseline));
 EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));
 EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));
 
diff --git a/change.log b/change.log
index 74102c0..704d8b2 100644
--- a/change.log
+++ b/change.log
@@ -1,6 +1,67 @@
 CHANGE LOG for Independent JPEG Group's JPEG software
 
 
+Version 8b  16-May-2010
+-----------------------
+
+Repair problem in new memory source manager with corrupt JPEG data.
+Thank to Ted Campbell and Samuel Chun for the report.
+
+
+Version 8a  28-Feb-2010
+-----------------------
+
+Writing tables-only datastreams via jpeg_write_tables works again.
+
+Support 32-bit BMPs (RGB image with Alpha channel) for read in cjpeg.
+Thank to Brett Blackham for the suggestion.
+
+
+Version 8  10-Jan-2010
+----------------------
+
+Add sanity check in BMP reader module to avoid cjpeg crash for empty input
+image (thank to Isaev Ildar of ISP RAS, Moscow, RU for reporting this error).
+
+Add data source and destination managers for read from and write to
+memory buffers.  New API functions jpeg_mem_src and jpeg_mem_dest.
+Thank to Roberto Boni from Italy for the suggestion.
+
+
+Version 7  27-Jun-2009
+----------------------
+
+cjpeg -quality option has been extended for support of separate quality
+settings for luminance and chrominance (or in general, for every provided
+quantization table slot).
+New API function jpeg_default_qtables() and q_scale_factor array in library.
+
+Support arithmetic entropy encoding and decoding.
+Added files jaricom.c, jcarith.c, jdarith.c.
+
+jpegtran has a new "lossless" cropping feature.
+
+Implement -perfect option in jpegtran, new API function
+jtransform_perfect_transform() in transupp. (DP 204_perfect.dpatch)
+
+Better error messages for jpegtran fopen failure.
+(DP 203_jpegtran_errmsg.dpatch)
+
+Fix byte order issue with 16bit PPM/PGM files in rdppm.c/wrppm.c:
+according to Netpbm, the de facto standard implementation of the PNM formats,
+the most significant byte is first. (DP 203_rdppm.dpatch)
+
+Add -raw option to rdjpgcom not to mangle the output.
+(DP 205_rdjpgcom_raw.dpatch)
+
+Make rdjpgcom locale aware. (DP 201_rdjpgcom_locale.dpatch)
+
+Add extern "C" to jpeglib.h.
+This avoids the need to put extern "C" { ... } around #include "jpeglib.h"
+in your C++ application.  Defining the symbol DONT_USE_EXTERN_C in the
+configuration prevents this. (DP 202_jpeglib.h_c++.dpatch)
+
+
 Version 6b  27-Mar-1998
 -----------------------
 
diff --git a/cjpeg.1 b/cjpeg.1
index d175a96..6fb7299 100644
--- a/cjpeg.1
+++ b/cjpeg.1
@@ -1,4 +1,4 @@
-.TH CJPEG 1 "20 March 1998"
+.TH CJPEG 1 "31 January 2012"
 .SH NAME
 cjpeg \- compress an image file to a JPEG file
 .SH SYNOPSIS
@@ -36,7 +36,7 @@
 .PP
 The basic switches are:
 .TP
-.BI \-quality " N"
+.BI \-quality " N[,...]"
 Scale quantization tables to adjust image quality.  Quality is 0 (worst) to
 100 (best); default is 75.  (See below for more info.)
 .TP
@@ -108,6 +108,36 @@
 .B \-baseline
 if you need to ensure compatibility at low quality values.)
 .PP
+The \fB-quality\fR option has been extended in this version of \fBcjpeg\fR to
+support separate quality settings for luminance and chrominance (or, in
+general, separate settings for every quantization table slot.)  The principle
+is the same as chrominance subsampling:  since the human eye is more sensitive
+to spatial changes in brightness than spatial changes in color, the chrominance
+components can be quantized more than the luminance components without
+incurring any visible image quality loss.  However, unlike subsampling, this
+feature reduces data in the frequency domain instead of the spatial domain,
+which allows for more fine-grained control.  This option is useful in
+quality-sensitive applications, for which the artifacts generated by
+subsampling may be unacceptable.
+.PP
+The \fB-quality\fR option accepts a comma-separated list of parameters, which
+respectively refer to the quality levels that should be assigned to the
+quantization table slots.  If there are more q-table slots than parameters,
+then the last parameter is replicated.  Thus, if only one quality parameter is
+given, this is used for both luminance and chrominance (slots 0 and 1,
+respectively), preserving the legacy behavior of cjpeg v6b and prior.
+More (or customized) quantization tables can be set with the \fB-qtables\fR
+option and assigned to components with the \fB-qslots\fR option (see the
+"wizard" switches below.)
+.PP
+JPEG files generated with separate luminance and chrominance quality are fully
+compliant with standard JPEG decoders.
+.PP
+.BR CAUTION:
+For this setting to be useful, be sure to pass an argument of \fB-sample 1x1\fR
+to \fBcjpeg\fR to disable chrominance subsampling.  Otherwise, the default
+subsampling level (2x2, AKA "4:2:0") will be used.
+.PP
 The
 .B \-progressive
 switch creates a "progressive JPEG" file.  In this type of JPEG file, the data
@@ -117,12 +147,15 @@
 display with each subsequent scan.  The final image is exactly equivalent to a
 standard JPEG file of the same quality setting, and the total file size is
 about the same --- often a little smaller.
-.B Caution:
-progressive JPEG is not yet widely implemented, so many decoders will be
-unable to view a progressive JPEG file at all.
 .PP
 Switches for advanced users:
 .TP
+.B \-arithmetic
+Use arithmetic coding.
+.B Caution:
+arithmetic coded JPEG is not yet widely implemented, so many decoders will be
+unable to view an arithmetic coded JPEG file at all.
+.TP
 .B \-dct int
 Use integer DCT method (default).
 .TP
@@ -211,7 +244,7 @@
 .PP
 The "wizard" switches are intended for experimentation with JPEG.  If you
 don't know what you are doing, \fBdon't use them\fR.  These switches are
-documented further in the file wizard.doc.
+documented further in the file wizard.txt.
 .SH EXAMPLES
 .LP
 This example compresses the PPM file foo.ppm with a quality factor of
@@ -276,11 +309,10 @@
 .SH AUTHOR
 Independent JPEG Group
 .SH BUGS
-Arithmetic coding is not supported for legal reasons.
-.PP
-GIF input files are no longer supported, to avoid the Unisys LZW patent.
-Use a Unisys-licensed program if you need to read a GIF file.  (Conversion
-of GIF files to JPEG is usually a bad idea anyway.)
+Support for GIF input files was removed in cjpeg v6b due to concerns over
+the Unisys LZW patent.  Although this patent expired in 2006, cjpeg still
+lacks GIF support, for these historical reasons.  (Conversion of GIF files to
+JPEG is usually a bad idea anyway.)
 .PP
 Not all variants of BMP and Targa file formats are supported.
 .PP
@@ -288,5 +320,3 @@
 .B \-targa
 switch is not a bug, it's a feature.  (It would be a bug if the Targa format
 designers had not been clueless.)
-.PP
-Still not as fast as we'd like.
diff --git a/cjpeg.c b/cjpeg.c
index f2a929f..0475c02 100644
--- a/cjpeg.c
+++ b/cjpeg.c
@@ -2,6 +2,8 @@
  * cjpeg.c
  *
  * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2008 by Guido Vollbeding.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -25,6 +27,7 @@
 
 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
 #include "jversion.h"		/* for version message */
+#include "config.h"
 
 #ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
 #ifdef __MWERKS__
@@ -149,7 +152,7 @@
 #endif
 
   fprintf(stderr, "Switches (names may be abbreviated):\n");
-  fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is useful range)\n");
+  fprintf(stderr, "  -quality N[,...]   Compression quality (0..100; 5-95 is useful range)\n");
   fprintf(stderr, "  -grayscale     Create monochrome JPEG file\n");
 #ifdef ENTROPY_OPT_SUPPORTED
   fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
@@ -161,6 +164,9 @@
   fprintf(stderr, "  -targa         Input file is Targa format (usually not needed)\n");
 #endif
   fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
+#endif
 #ifdef DCT_ISLOW_SUPPORTED
   fprintf(stderr, "  -dct int       Use integer DCT method%s\n",
 	  (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
@@ -181,9 +187,6 @@
   fprintf(stderr, "  -outfile name  Specify name for output file\n");
   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
   fprintf(stderr, "Switches for wizards:\n");
-#ifdef C_ARITH_CODING_SUPPORTED
-  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
-#endif
   fprintf(stderr, "  -baseline      Force baseline quantization tables\n");
   fprintf(stderr, "  -qtables file  Use quantization tables given in file\n");
   fprintf(stderr, "  -qslots N[,...]    Set component quantization tables\n");
@@ -209,21 +212,16 @@
 {
   int argn;
   char * arg;
-  int quality;			/* -quality parameter */
-  int q_scale_factor;		/* scaling percentage for -qtables */
   boolean force_baseline;
   boolean simple_progressive;
+  char * qualityarg = NULL;	/* saves -quality parm if any */
   char * qtablefile = NULL;	/* saves -qtables filename if any */
   char * qslotsarg = NULL;	/* saves -qslots parm if any */
   char * samplearg = NULL;	/* saves -sample parm if any */
   char * scansarg = NULL;	/* saves -scans parm if any */
 
   /* Set up default JPEG parameters. */
-  /* Note that default -quality level need not, and does not,
-   * match the default scaling for an explicit -qtables argument.
-   */
-  quality = 75;			/* default -quality value */
-  q_scale_factor = 100;		/* default to no scaling for -qtables */
+
   force_baseline = FALSE;	/* by default, allow 16-bit quantizers */
   simple_progressive = FALSE;
   is_targa = FALSE;
@@ -277,8 +275,11 @@
       static boolean printed_version = FALSE;
 
       if (! printed_version) {
-	fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
-		JVERSION, JCOPYRIGHT);
+	fprintf(stderr, "%s version %s (build %s)\n",
+		PACKAGE_NAME, VERSION, BUILD);
+	fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+	fprintf(stderr, "Emulating The Independent JPEG Group's libjpeg, version %s\n\n",
+		JVERSION);
 	printed_version = TRUE;
       }
       cinfo->err->trace_level++;
@@ -328,13 +329,10 @@
 #endif
 
     } else if (keymatch(arg, "quality", 1)) {
-      /* Quality factor (quantization table scaling factor). */
+      /* Quality ratings (quantization table scaling factors). */
       if (++argn >= argc)	/* advance to next argument */
 	usage();
-      if (sscanf(argv[argn], "%d", &quality) != 1)
-	usage();
-      /* Change scale factor in case -qtables is present. */
-      q_scale_factor = jpeg_quality_scaling(quality);
+      qualityarg = argv[argn];
 
     } else if (keymatch(arg, "qslots", 2)) {
       /* Quantization table slot numbers. */
@@ -382,7 +380,7 @@
        * default sampling factors.
        */
 
-    } else if (keymatch(arg, "scans", 2)) {
+    } else if (keymatch(arg, "scans", 4)) {
       /* Set scan script. */
 #ifdef C_MULTISCAN_FILES_SUPPORTED
       if (++argn >= argc)	/* advance to next argument */
@@ -422,11 +420,12 @@
 
     /* Set quantization tables for selected quality. */
     /* Some or all may be overridden if -qtables is present. */
-    jpeg_set_quality(cinfo, quality, force_baseline);
+    if (qualityarg != NULL)	/* process -quality if it was present */
+      if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
+	usage();
 
     if (qtablefile != NULL)	/* process -qtables if it was present */
-      if (! read_quant_tables(cinfo, qtablefile,
-			      q_scale_factor, force_baseline))
+      if (! read_quant_tables(cinfo, qtablefile, force_baseline))
 	usage();
 
     if (qslotsarg != NULL)	/* process -qslots if it was present */
diff --git a/coderules.doc b/coderules.txt
similarity index 98%
rename from coderules.doc
rename to coderules.txt
index 0ab5d9b..357929f 100644
--- a/coderules.doc
+++ b/coderules.txt
@@ -103,7 +103,7 @@
 
 4. Don't use static variables except for read-only constant tables.  Variables
 that should be private to a module can be placed into private structures (see
-the system architecture document, structure.doc).
+the system architecture document, structure.txt).
 
 5. Source file names should begin with "j" for files that are part of the
 library proper; source files that are not part of the library, such as cjpeg.c
diff --git a/configure.ac b/configure.ac
index b79876f..b4d037e 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.0.2])
+AC_INIT([libjpeg-turbo], [1.1.2])
 BUILD=`date +%Y%m%d`
 
 AM_INIT_AUTOMAKE([-Wall foreign dist-bzip2])
@@ -13,10 +13,9 @@
 
 # Checks for programs.
 SAVED_CFLAGS=${CFLAGS}
-SAVED_CXXFLAGS=${CXXFLAGS}
+SAVED_CPPFLAGS=${CPPFLAGS}
 AC_PROG_CPP
 AC_PROG_CC
-AC_PROG_CXX
 AC_PROG_INSTALL
 AC_PROG_LIBTOOL
 AC_PROG_LN_S
@@ -28,33 +27,12 @@
 [AC_MSG_RESULT(no)
 AC_DEFINE([INCOMPLETE_TYPES_BROKEN],[1],[Compiler does not support pointers to undefined structures.])])
 
-AC_MSG_CHECKING([whether the linker supports version scripts])
-VERSION_SCRIPT=no
-LDVER=`$LD --help </dev/null 2>&1 | grep "\-\-version-script"`
-if test "$LDVER"; then
-  VERSION_SCRIPT=yes
-  VERSION_SCRIPT_FLAG=-Wl,--version-script,
-  AC_MSG_RESULT(yes)
-else
-  LDVER=`$LD --help </dev/null 2>&1 | grep "\-M"`
-  if test "$LDVER"; then
-    VERSION_SCRIPT=yes
-    VERSION_SCRIPT_FLAG=-Wl,-M,
-    AC_MSG_RESULT(yes)
-  else
-    AC_MSG_RESULT(no)
-  fi
-fi
-
-AM_CONDITIONAL(VERSION_SCRIPT, test "x$VERSION_SCRIPT" = "xyes")
-AC_SUBST(VERSION_SCRIPT_FLAG)
-
 if test "x${GCC}" = "xyes"; then
   if test "x${SAVED_CFLAGS}" = "x"; then
     CFLAGS=-O3
   fi
-  if test "x${SAVED_CXXFLAGS}" = "x"; then
-    CXXFLAGS=-O3
+  if test "x${SAVED_CPPFLAGS}" = "x"; then
+    CPPFLAGS=-Wall
   fi
 fi
 
@@ -63,9 +41,6 @@
   if test "x${SAVED_CFLAGS}" = "x"; then
     CFLAGS=-xO5
   fi
-  if test "x${SAVED_CXXFLAGS}" = "x"; then
-    CXXFLAGS=-xO5
-  fi
 fi
 
 # Checks for libraries.
@@ -123,9 +98,107 @@
 	[AC_DEFINE([NEED_BSD_STRINGS], 1,
 		   [Define if you have BSD-like bzero and bcopy])])
 
+AC_MSG_CHECKING([libjpeg API version])
+AC_ARG_VAR(JPEG_LIB_VERSION, [libjpeg API version (62, 70, or 80)])
+if test "x$JPEG_LIB_VERSION" = "x"; then
+    AC_ARG_WITH([jpeg7],
+        AC_HELP_STRING([--with-jpeg7], [Emulate libjpeg v7 API/ABI (this makes libjpeg-turbo backward incompatible with libjpeg v6b.)]))
+    AC_ARG_WITH([jpeg8],
+        AC_HELP_STRING([--with-jpeg8], [Emulate libjpeg v8 API/ABI (this makes libjpeg-turbo backward incompatible with libjpeg v6b.)]))
+    if test "x${with_jpeg8}" = "xyes"; then
+        JPEG_LIB_VERSION=80
+    else
+        if test "x${with_jpeg7}" = "xyes"; then
+            JPEG_LIB_VERSION=70
+        else
+            JPEG_LIB_VERSION=62
+        fi
+    fi
+fi
+JPEG_LIB_VERSION_DECIMAL=`expr $JPEG_LIB_VERSION / 10`.`expr $JPEG_LIB_VERSION % 10`
+AC_SUBST(JPEG_LIB_VERSION_DECIMAL)
+AC_MSG_RESULT([$JPEG_LIB_VERSION_DECIMAL])
+AC_DEFINE_UNQUOTED(JPEG_LIB_VERSION, [$JPEG_LIB_VERSION], [libjpeg API version])
+
+AC_MSG_CHECKING([libjpeg shared library version])
+AC_ARG_VAR(SO_MAJOR_VERSION, [Major version of the libjpeg-turbo shared library (default is determined by the API version)])
+AC_ARG_VAR(SO_MINOR_VERSION, [Minor version of the libjpeg-turbo shared library (default is determined by the API version)])
+if test "x$SO_MAJOR_VERSION" = "x"; then
+    case "$JPEG_LIB_VERSION" in
+        62)  SO_MAJOR_VERSION=$JPEG_LIB_VERSION ;;
+        *)   SO_MAJOR_VERSION=`expr $JPEG_LIB_VERSION / 10` ;;
+    esac
+fi
+if test "x$SO_MINOR_VERSION" = "x"; then
+    case "$JPEG_LIB_VERSION" in
+        80)  SO_MINOR_VERSION=2 ;;
+        *)   SO_MINOR_VERSION=0 ;;
+    esac
+fi
+AC_MSG_RESULT([$SO_MAJOR_VERSION:$SO_MINOR_VERSION])
+AC_SUBST(SO_MAJOR_VERSION)
+AC_SUBST(SO_MINOR_VERSION)
+
+VERSION_SCRIPT=yes
+AC_ARG_ENABLE([ld-version-script],
+  AS_HELP_STRING([--disable-ld-version-script],
+    [Disable linker version script for libjpeg-turbo (default is to use linker version script if the linker supports it)]),
+    [VERSION_SCRIPT=$enableval], [])
+
+AC_MSG_CHECKING([whether the linker supports version scripts])
+SAVED_LDFLAGS="$LDFLAGS"
+LDFLAGS="$LDFLAGS -Wl,--version-script,conftest.map"
+cat > conftest.map <<EOF
+VERS_1 {
+  global: *;
+};
+EOF
+AC_LINK_IFELSE(AC_LANG_PROGRAM([], []),
+  [VERSION_SCRIPT_FLAG=-Wl,--version-script,; AC_MSG_RESULT([yes (GNU style)])], [])
+if test "x$VERSION_SCRIPT_FLAG" = "x"; then
+  LDFLAGS="$SAVED_LDFLAGS -Wl,-M,conftest.map"
+  AC_LINK_IFELSE(AC_LANG_PROGRAM([], []),
+    [VERSION_SCRIPT_FLAG=-Wl,-M,; AC_MSG_RESULT([yes (Sun style)])], [])
+fi
+if test "x$VERSION_SCRIPT_FLAG" = "x"; then
+  VERSION_SCRIPT=no
+  AC_MSG_RESULT(no)
+fi
+LDFLAGS="$SAVED_LDFLAGS"
+
+AC_MSG_CHECKING([whether to use version script when building libjpeg-turbo])
+AC_MSG_RESULT($VERSION_SCRIPT)
+
+AM_CONDITIONAL(VERSION_SCRIPT, test "x$VERSION_SCRIPT" = "xyes")
+AC_SUBST(VERSION_SCRIPT_FLAG)
+
+AC_MSG_CHECKING([whether to include arithmetic encoding support])
+AC_ARG_WITH([arith-enc],
+    AC_HELP_STRING([--without-arith-enc], [Omit arithmetic encoding support]))
+if test "x$with_arith_enc" = "xno"; then
+    AC_MSG_RESULT(no)
+else
+    AC_DEFINE([C_ARITH_CODING_SUPPORTED], [1], [Support arithmetic encoding])
+    AC_MSG_RESULT(yes)
+fi
+AM_CONDITIONAL([WITH_ARITH_ENC], [test "x$with_arith_enc" != "xno"])
+
+AC_MSG_CHECKING([whether to include arithmetic decoding support])
+AC_ARG_WITH([arith-dec],
+    AC_HELP_STRING([--without-arith-dec], [Omit arithmetic decoding support]))
+if test "x$with_arith_dec" = "xno"; then
+    AC_MSG_RESULT(no)
+else
+    AC_DEFINE([D_ARITH_CODING_SUPPORTED], [1], [Support arithmetic decoding])
+    AC_MSG_RESULT(yes)
+fi
+AM_CONDITIONAL([WITH_ARITH_DEC], [test "x$with_arith_dec" != "xno"])
+
+AM_CONDITIONAL([WITH_ARITH], [test "x$with_arith_dec" != "xno" -o "x$with_arith_enc" != "xno"])
+
 # SIMD is optional
 AC_ARG_WITH([simd],
-    AC_HELP_STRING([--without-simd],[Omit accelerated SIMD routines.]))
+    AC_HELP_STRING([--without-simd],[Omit SIMD extensions.]))
 if test "x${with_simd}" != "xno"; then
   # Check if we're on a supported CPU
   AC_MSG_CHECKING([if we have SIMD optimisations for cpu type])
@@ -171,6 +244,7 @@
 AC_SUBST(RPMARCH)
 AC_SUBST(DEBARCH)
 AC_SUBST(BUILD)
+AC_DEFINE_UNQUOTED([BUILD], "$BUILD", [Build number])
 
 # jconfig.h is the file we use, but we have another before that to
 # fool autoheader. the reason is that we include this header in our
@@ -178,5 +252,15 @@
 # jconfig.h is a minimal version that allows this package to be built
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_HEADERS([jconfig.h])
+AC_CONFIG_FILES([pkgscripts/libjpeg-turbo.spec:release/libjpeg-turbo.spec.in])
+AC_CONFIG_FILES([pkgscripts/makecygwinpkg:release/makecygwinpkg.in])
+AC_CONFIG_FILES([pkgscripts/makedpkg:release/makedpkg.in])
+AC_CONFIG_FILES([pkgscripts/makemacpkg:release/makemacpkg.in])
+AC_CONFIG_FILES([pkgscripts/Description.plist:release/Description.plist.in])
+AC_CONFIG_FILES([pkgscripts/Info.plist:release/Info.plist.in])
+AC_CONFIG_FILES([pkgscripts/uninstall:release/uninstall.in])
+AC_CONFIG_FILES([pkgscripts/makesunpkg:release/makesunpkg.in])
+AC_CONFIG_FILES([pkgscripts/pkginfo:release/pkginfo.in])
+AC_CONFIG_FILES([libjpeg.map])
 AC_CONFIG_FILES([Makefile simd/Makefile])
 AC_OUTPUT
diff --git a/djpeg.1 b/djpeg.1
index 11beb6a..e5e46f2 100644
--- a/djpeg.1
+++ b/djpeg.1
@@ -1,4 +1,4 @@
-.TH DJPEG 1 "22 August 1997"
+.TH DJPEG 1 "11 October 2010"
 .SH NAME
 djpeg \- decompress a JPEG file to an image file
 .SH SYNOPSIS
@@ -243,11 +243,7 @@
 .SH AUTHOR
 Independent JPEG Group
 .SH BUGS
-Arithmetic coding is not supported for legal reasons.
-.PP
 To avoid the Unisys LZW patent,
 .B djpeg
 produces uncompressed GIF files.  These are larger than they should be, but
 are readable by standard GIF decoders.
-.PP
-Still not as fast as we'd like.
diff --git a/djpeg.c b/djpeg.c
index e099e90..5fc4027 100644
--- a/djpeg.c
+++ b/djpeg.c
@@ -2,6 +2,7 @@
  * djpeg.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -25,6 +26,7 @@
 
 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
 #include "jversion.h"		/* for version message */
+#include "config.h"
 
 #include <ctype.h>		/* to declare isprint() */
 
@@ -240,8 +242,11 @@
       static boolean printed_version = FALSE;
 
       if (! printed_version) {
-	fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
-		JVERSION, JCOPYRIGHT);
+	fprintf(stderr, "%s version %s (build %s)\n",
+		PACKAGE_NAME, VERSION, BUILD);
+	fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+	fprintf(stderr, "Emulating The Independent JPEG Group's libjpeg, version %s\n\n",
+		JVERSION);
 	printed_version = TRUE;
       }
       cinfo->err->trace_level++;
@@ -455,7 +460,7 @@
    * APP12 is used by some digital camera makers for textual info,
    * so we provide the ability to display it as text.
    * If you like, additional APPn marker types can be selected for display,
-   * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
+   * but don't try to override APP0 or APP14 this way (see libjpeg.txt).
    */
   jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
   jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
diff --git a/example.c b/example.c
index 7fc354f..1d6f6cc 100644
--- a/example.c
+++ b/example.c
@@ -3,7 +3,7 @@
  *
  * This file illustrates how to use the IJG code as a subroutine library
  * to read or write JPEG image files.  You should look at this code in
- * conjunction with the documentation file libjpeg.doc.
+ * conjunction with the documentation file libjpeg.txt.
  *
  * This code will not do anything useful as-is, but it may be helpful as a
  * skeleton for constructing routines that call the JPEG library.  
@@ -196,7 +196,7 @@
  * files for anything that doesn't fit within the maximum-memory setting.
  * (Note that temp files are NOT needed if you use the default parameters.)
  * On some systems you may need to set up a signal handler to ensure that
- * temporary files are deleted if the program is interrupted.  See libjpeg.doc.
+ * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
  *
  * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
  * files to be compatible with everyone else's.  If you cannot readily read
@@ -335,7 +335,7 @@
   /* We can ignore the return value from jpeg_read_header since
    *   (a) suspension is not possible with the stdio data source, and
    *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
-   * See libjpeg.doc for more info.
+   * See libjpeg.txt for more info.
    */
 
   /* Step 4: set parameters for decompression */
@@ -413,14 +413,14 @@
  * In the above code, we ignored the return value of jpeg_read_scanlines,
  * which is the number of scanlines actually read.  We could get away with
  * this because we asked for only one line at a time and we weren't using
- * a suspending data source.  See libjpeg.doc for more info.
+ * a suspending data source.  See libjpeg.txt for more info.
  *
  * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
  * we should have done it beforehand to ensure that the space would be
  * counted against the JPEG max_memory setting.  In some systems the above
  * code would risk an out-of-memory error.  However, in general we don't
  * know the output image dimensions before jpeg_start_decompress(), unless we
- * call jpeg_calc_output_dimensions().  See libjpeg.doc for more about this.
+ * call jpeg_calc_output_dimensions().  See libjpeg.txt for more about this.
  *
  * Scanlines are returned in the same order as they appear in the JPEG file,
  * which is standardly top-to-bottom.  If you must emit data bottom-to-top,
@@ -429,5 +429,5 @@
  *
  * As with compression, some operating modes may require temporary files.
  * On some systems you may need to set up a signal handler to ensure that
- * temporary files are deleted if the program is interrupted.  See libjpeg.doc.
+ * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
  */
diff --git a/filelist.doc b/filelist.txt
similarity index 88%
rename from filelist.doc
rename to filelist.txt
index e14982c..2f905a6 100644
--- a/filelist.doc
+++ b/filelist.txt
@@ -1,6 +1,6 @@
 IJG JPEG LIBRARY:  FILE LIST
 
-Copyright (C) 1994-1998, Thomas G. Lane.
+Copyright (C) 1994-2010, Thomas G. Lane, Guido Vollbeding, D. R. Commander.
 This file is part of the Independent JPEG Group's software.
 For conditions of distribution and use, see the accompanying README file.
 
@@ -74,8 +74,9 @@
 jfdctflt.c	Forward DCT using floating-point arithmetic.
 jchuff.c	Huffman entropy coding for sequential JPEG.
 jcphuff.c	Huffman entropy coding for progressive JPEG.
+jcarith.c	Arithmetic entropy coding.
 jcmarker.c	JPEG marker writing.
-jdatadst.c	Data destination manager for stdio output.
+jdatadst.c	Data destination managers for memory and stdio output.
 
 Decompression side of the library:
 
@@ -87,6 +88,7 @@
 jdmarker.c	JPEG marker reading.
 jdhuff.c	Huffman entropy decoding for sequential JPEG.
 jdphuff.c	Huffman entropy decoding for progressive JPEG.
+jdarith.c	Arithmetic entropy decoding.
 jddctmgr.c	IDCT manager (IDCT implementation selection & control).
 jidctint.c	Inverse DCT using slow-but-accurate integer method.
 jidctfst.c	Inverse DCT using faster, less accurate integer method.
@@ -98,10 +100,12 @@
 jquant1.c	One-pass color quantization using a fixed-spacing colormap.
 jquant2.c	Two-pass color quantization using a custom-generated colormap.
 		Also handles one-pass quantization to an externally given map.
-jdatasrc.c	Data source manager for stdio input.
+jdatasrc.c	Data source managers for memory and stdio input.
 
 Support files for both compression and decompression:
 
+jaricom.c	Tables for common use in arithmetic entropy encoding and
+		decoding routines.
 jerror.c	Standard error handling routines (application replaceable).
 jmemmgr.c	System-independent (more or less) memory management code.
 jutils.c	Miscellaneous utility routines.
@@ -118,7 +122,7 @@
 jmemmac.c	Custom implementation for Apple Macintosh.
 
 Exactly one of the system-dependent modules should be configured into an
-installed JPEG library (see install.doc for hints about which one to use).
+installed JPEG library (see install.txt for hints about which one to use).
 On unusual systems you may find it worthwhile to make a special
 system-dependent memory manager.
 
@@ -184,27 +188,27 @@
 Documentation (see README for a guide to the documentation files):
 
 README		Master documentation file.
-*.doc		Other documentation files.
+*.txt		Other documentation files.
 *.1		Documentation in Unix man page format.
 change.log	Version-to-version change highlights.
 example.c	Sample code for calling JPEG library.
 
-Configuration/installation files and programs (see install.doc for more info):
+Configuration/installation files and programs (see install.txt for more info):
 
 configure	Unix shell script to perform automatic configuration.
-ltconfig	Support scripts for configure (from GNU libtool).
-ltmain.sh
+configure.ac	Source file for use with Autoconf to generate configure.
+ltmain.sh	Support scripts for configure (from GNU libtool).
 config.guess
 config.sub
+depcomp
+missing
 install-sh	Install shell script for those Unix systems lacking one.
-ckconfig.c	Program to generate jconfig.h on non-Unix systems.
-jconfig.doc	Template for making jconfig.h by hand.
-makefile.*	Sample makefiles for particular systems.
-jconfig.*	Sample jconfig.h for particular systems.
-ansi2knr.c	De-ANSIfier for pre-ANSI C compilers (courtesy of
-		L. Peter Deutsch and Aladdin Enterprises).
+Makefile.in	Makefile input for configure.
+Makefile.am	Source file for use with Automake to generate Makefile.in.
+jconfig.txt	Template for making jconfig.h by hand.
+aclocal.m4	M4 macro definitions for use with Autoconf.
 
-Test files (see install.doc for test procedure):
+Test files (see install.txt for test procedure):
 
 test*.*		Source and comparison files for confidence test.
 		These are binary image files, NOT text files.
diff --git a/install.doc b/install.txt
similarity index 92%
rename from install.doc
rename to install.txt
index 3702b98..1327dc4 100644
--- a/install.doc
+++ b/install.txt
@@ -1,6 +1,6 @@
 INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software
 
-Copyright (C) 1991-1998, Thomas G. Lane.
+Copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding.
 This file is part of the Independent JPEG Group's software.
 For conditions of distribution and use, see the accompanying README file.
 
@@ -94,18 +94,13 @@
 for GNU configure scripts.  It makes a few assumptions that you may want to
 override.  You can do this by providing optional switches to configure:
 
-* If you want to build libjpeg as a shared library, say
-	./configure --enable-shared
-To get both shared and static libraries, say
-	./configure --enable-shared --enable-static
-Note that these switches invoke GNU libtool to take care of system-dependent
-shared library building methods.  If things don't work this way, please try
-running configure without either switch; that should build a static library
-without using libtool.  If that works, your problem is probably with libtool
-not with the IJG code.  libtool is fairly new and doesn't support all flavors
-of Unix yet.  (You might be able to find a newer version of libtool than the
-one included with libjpeg; see ftp.gnu.org.  Report libtool problems to
-bug-libtool@gnu.org.)
+* Configure will build both static and shared libraries, if possible.
+If you want to build libjpeg only as a static library, say
+	./configure --disable-shared
+If you want to build libjpeg only as a shared library, say
+	./configure --disable-static
+Configure uses GNU libtool to take care of system-dependent shared library
+building methods.
 
 * Configure will use gcc (GNU C compiler) if it's available, otherwise cc.
 To force a particular compiler to be selected, use the CC option, for example
@@ -115,10 +110,10 @@
 	./configure CC='cc -Aa'
 to get HP's compiler to run in ANSI mode.
 
-* The default CFLAGS setting is "-O" for non-gcc compilers, "-O2" for gcc.
+* The default CFLAGS setting is "-g" for non-gcc compilers, "-g -O2" for gcc.
 You can override this by saying, for example,
-	./configure CFLAGS='-g'
-if you want to compile with debugging support.
+	./configure CFLAGS='-O2'
+if you want to compile without debugging support.
 
 * Configure will set up the makefile so that "make install" will install files
 into /usr/local/bin, /usr/local/man, etc.  You can specify an installation
@@ -153,7 +148,8 @@
 makefile.mc6	jconfig.mc6	MS-DOS, Microsoft C (16-bit only)
 makefile.wat	jconfig.wat	MS-DOS, OS/2, or Windows NT, Watcom C
 makefile.vc	jconfig.vc	Windows NT/95, MS Visual C++
-make*.ds	jconfig.vc	Windows NT/95, MS Developer Studio
+make*.vc6	jconfig.vc	Windows NT/95, MS Visual C++ 6
+make*.v10	jconfig.vc	Windows NT/95, MS Visual C++ 2010 (v10)
 makefile.mms	jconfig.vms	Digital VMS, with MMS software
 makefile.vms	jconfig.vms	Digital VMS, without MMS software
 
@@ -166,8 +162,8 @@
 --------------------------------
 
 First, generate a jconfig.h file.  If you are moderately familiar with C,
-the comments in jconfig.doc should be enough information to do this; just
-copy jconfig.doc to jconfig.h and edit it appropriately.  Otherwise, you may
+the comments in jconfig.txt should be enough information to do this; just
+copy jconfig.txt to jconfig.h and edit it appropriately.  Otherwise, you may
 prefer to use the ckconfig.c program.  You will need to compile and execute
 ckconfig.c by hand --- we hope you know at least enough to do that.
 ckconfig.c may not compile the first try (in fact, the whole idea is for it
@@ -447,8 +443,8 @@
 
 The PPM reader (rdppm.c) can read 12-bit data from either text-format or
 binary-format PPM and PGM files.  Binary-format PPM/PGM files which have a
-maxval greater than 255 are assumed to use 2 bytes per sample, LSB first
-(little-endian order).  As of early 1995, 2-byte binary format is not
+maxval greater than 255 are assumed to use 2 bytes per sample, MSB first
+(big-endian order).  As of early 1995, 2-byte binary format is not
 officially supported by the PBMPLUS library, but it is expected that a
 future release of PBMPLUS will support it.  Note that the PPM reader will
 read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming
@@ -521,7 +517,7 @@
 "#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h.  Even if you don't change
 the default, you should redefine JDCT_FASTEST, which is the method selected
 by djpeg's -fast switch.  Don't forget to update the documentation files
-(usage.doc and/or cjpeg.1, djpeg.1) to agree with what you've done.
+(usage.txt and/or cjpeg.1, djpeg.1) to agree with what you've done.
 
 If access to "short" arrays is slow on your machine, it may be a win to
 define type JCOEF as int rather than short.  This will cost a good deal of
@@ -538,7 +534,7 @@
 and experimenting with any optional optimizations such as loop unrolling.
 (Unfortunately, far too many compilers have optimizer bugs ... be prepared to
 back off if the code fails self-test.)  If you do any experimentation along
-these lines, please report the optimal settings to jpeg-info@uunet.uu.net so
+these lines, please report the optimal settings to jpeg-info@jpegclub.org so
 we can mention them in future releases.  Be sure to specify your machine and
 compiler version.
 
@@ -547,7 +543,7 @@
 ==========================
 
 We welcome reports on changes needed for systems not mentioned here.  Submit
-'em to jpeg-info@uunet.uu.net.  Also, if configure or ckconfig.c is wrong
+'em to jpeg-info@jpegclub.org.  Also, if configure or ckconfig.c is wrong
 about how to configure the JPEG software for your system, please let us know.
 
 
@@ -568,7 +564,7 @@
 lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h'
 dependency section.
 
-Copy jconfig.doc to jconfig.h.  Edit jconfig.h to define TWO_FILE_COMMANDLINE
+Copy jconfig.txt to jconfig.h.  Edit jconfig.h to define TWO_FILE_COMMANDLINE
 and CHAR_IS_UNSIGNED.
 
 Run the makefile using !AMU not !Make.  If you want to use the 'clean' and
@@ -587,7 +583,7 @@
 
 
 Atari ST/STE/TT:
- 
+
 Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st
 to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively.  The
 project files should work as-is with Pure C.  For Turbo C, change library
@@ -610,7 +606,8 @@
 
 We haven't bothered to include project files for rdjpgcom and wrjpgcom.
 Those source files should just be compiled by themselves; they don't
-depend on the JPEG library.
+depend on the JPEG library.  You can use the default.prj project file
+of the Pure C distribution to make the programs.
 
 There is a bug in some older versions of the Turbo C library which causes the
 space used by temporary files created with "tmpfile()" not to be freed after
@@ -872,6 +869,7 @@
 warning if you include both jpeglib.h and windef.h (which windows.h
 includes).  To suppress the warning, you can put "#ifndef FAR"/"#endif"
 around the line "#define FAR" in jmorecfg.h.
+(Something like this is already in jmorecfg.h, by the way.)
 
 When using the library in a Windows application, you will almost certainly
 want to modify or replace the error handler module jerror.c, since our
@@ -890,7 +888,7 @@
 
 The proper solution for problem 2 is to return control to your calling
 application after a library error.  This can be done with the setjmp/longjmp
-technique discussed in libjpeg.doc and illustrated in example.c.  (NOTE:
+technique discussed in libjpeg.txt and illustrated in example.c.  (NOTE:
 some older Windows C compilers provide versions of setjmp/longjmp that
 don't actually work under Windows.  You may need to use the Windows system
 functions Catch and Throw instead.)
@@ -1000,32 +998,67 @@
 the Developer Studio environment, you may prefer the DevStudio project
 files; see below.)
 
-Some users feel that it's easier to call the library from C++ code if you
-force VC++ to treat the library as C++ code, which you can do by renaming
-all the *.c files to *.cpp (and adjusting the makefile to match).  This
-avoids the need to put extern "C" { ... } around #include "jpeglib.h" in
-your C++ application.
+IJG JPEG 7 adds extern "C" to jpeglib.h.  This avoids the need to put
+extern "C" { ... } around #include "jpeglib.h" in your C++ application.
+You can also force VC++ to treat the library as C++ code by renaming
+all the *.c files to *.cpp (and adjusting the makefile to match).
+In this case you also need to define the symbol DONT_USE_EXTERN_C in
+the configuration to prevent jpeglib.h from using extern "C".
 
 
-Microsoft Windows, Microsoft Developer Studio:
+Microsoft Windows, Microsoft Visual C++ 6 Developer Studio:
 
-We include makefiles that should work as project files in DevStudio 4.2 or
+We include makefiles that should work as project files in DevStudio 6.0 or
 later.  There is a library makefile that builds the IJG library as a static
-Win32 library, and an application makefile that builds the sample applications
+Win32 library, and application makefiles that build the sample applications
 as Win32 console applications.  (Even if you only want the library, we
 recommend building the applications so that you can run the self-test.)
 
 To use:
-1. Copy jconfig.vc to jconfig.h, makelib.ds to jpeg.mak, and
-   makeapps.ds to apps.mak.  (Note that the renaming is critical!)
-2. Click on the .mak files to construct project workspaces.
-   (If you are using DevStudio more recent than 4.2, you'll probably
-   get a message saying that the makefiles are being updated.)
-3. Build the library project, then the applications project.
-4. Move the application .exe files from `app`\Release to an
+1. Open the command prompt, change to the main directory and execute the
+   command line
+	NMAKE /f makefile.vc  setup-vc6
+   This will move jconfig.vc to jconfig.h and makefiles to project files.
+   (Note that the renaming is critical!)
+2. Open the workspace file jpeg.dsw, build the library project.
+   (If you are using DevStudio more recent than 6.0, you'll probably
+   get a message saying that the project files are being updated.)
+3. Open the workspace file apps.dsw, build the application projects.
+4. To perform the self-test, execute the command line
+	NMAKE /f makefile.vc  test-build
+5. Move the application .exe files from `app`\Release to an
    appropriate location on your path.
-5. To perform the self-test, execute the command line
-	NMAKE /f makefile.vc  test
+
+
+Microsoft Windows, Microsoft Visual C++ 2010 Developer Studio (v10):
+
+We include makefiles that should work as project files in Visual Studio
+2010 or later.  There is a library makefile that builds the IJG library
+as a static Win32 library, and application makefiles that build the sample
+applications as Win32 console applications.  (Even if you only want the
+library, we recommend building the applications so that you can run the
+self-test.)
+
+To use:
+1. Open the command prompt, change to the main directory and execute the
+   command line
+	NMAKE /f makefile.vc  setup-v10
+   This will move jconfig.vc to jconfig.h and makefiles to project files.
+   (Note that the renaming is critical!)
+2. Open the solution file jpeg.sln, build the library project.
+   (If you are using Visual Studio more recent than 2010 (v10), you'll
+   probably get a message saying that the project files are being updated.)
+3. Open the solution file apps.sln, build the application projects.
+4. To perform the self-test, execute the command line
+	NMAKE /f makefile.vc  test-build
+5. Move the application .exe files from `app`\Release to an
+   appropriate location on your path.
+
+Note:
+There seems to be an optimization bug in the compiler which causes the
+self-test to fail with the color quantization option.
+We have disabled optimization for the file jquant2.c in the library
+project file which causes the self-test to pass properly.
 
 
 OS/2, Borland C++:
diff --git a/jaricom.c b/jaricom.c
new file mode 100644
index 0000000..f43e2ea
--- /dev/null
+++ b/jaricom.c
@@ -0,0 +1,153 @@
+/*
+ * jaricom.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains probability estimation tables for common use in
+ * arithmetic entropy encoding and decoding routines.
+ *
+ * This data represents Table D.2 in the JPEG spec (ISO/IEC IS 10918-1
+ * and CCITT Recommendation ITU-T T.81) and Table 24 in the JBIG spec
+ * (ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* The following #define specifies the packing of the four components
+ * into the compact INT32 representation.
+ * Note that this formula must match the actual arithmetic encoder
+ * and decoder implementation.  The implementation has to be changed
+ * if this formula is changed.
+ * The current organization is leaned on Markus Kuhn's JBIG
+ * implementation (jbig_tab.c).
+ */
+
+#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
+
+const INT32 jpeg_aritab[113+1] = {
+/*
+ * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
+ */
+  V(   0, 0x5a1d,   1,   1, 1 ),
+  V(   1, 0x2586,  14,   2, 0 ),
+  V(   2, 0x1114,  16,   3, 0 ),
+  V(   3, 0x080b,  18,   4, 0 ),
+  V(   4, 0x03d8,  20,   5, 0 ),
+  V(   5, 0x01da,  23,   6, 0 ),
+  V(   6, 0x00e5,  25,   7, 0 ),
+  V(   7, 0x006f,  28,   8, 0 ),
+  V(   8, 0x0036,  30,   9, 0 ),
+  V(   9, 0x001a,  33,  10, 0 ),
+  V(  10, 0x000d,  35,  11, 0 ),
+  V(  11, 0x0006,   9,  12, 0 ),
+  V(  12, 0x0003,  10,  13, 0 ),
+  V(  13, 0x0001,  12,  13, 0 ),
+  V(  14, 0x5a7f,  15,  15, 1 ),
+  V(  15, 0x3f25,  36,  16, 0 ),
+  V(  16, 0x2cf2,  38,  17, 0 ),
+  V(  17, 0x207c,  39,  18, 0 ),
+  V(  18, 0x17b9,  40,  19, 0 ),
+  V(  19, 0x1182,  42,  20, 0 ),
+  V(  20, 0x0cef,  43,  21, 0 ),
+  V(  21, 0x09a1,  45,  22, 0 ),
+  V(  22, 0x072f,  46,  23, 0 ),
+  V(  23, 0x055c,  48,  24, 0 ),
+  V(  24, 0x0406,  49,  25, 0 ),
+  V(  25, 0x0303,  51,  26, 0 ),
+  V(  26, 0x0240,  52,  27, 0 ),
+  V(  27, 0x01b1,  54,  28, 0 ),
+  V(  28, 0x0144,  56,  29, 0 ),
+  V(  29, 0x00f5,  57,  30, 0 ),
+  V(  30, 0x00b7,  59,  31, 0 ),
+  V(  31, 0x008a,  60,  32, 0 ),
+  V(  32, 0x0068,  62,  33, 0 ),
+  V(  33, 0x004e,  63,  34, 0 ),
+  V(  34, 0x003b,  32,  35, 0 ),
+  V(  35, 0x002c,  33,   9, 0 ),
+  V(  36, 0x5ae1,  37,  37, 1 ),
+  V(  37, 0x484c,  64,  38, 0 ),
+  V(  38, 0x3a0d,  65,  39, 0 ),
+  V(  39, 0x2ef1,  67,  40, 0 ),
+  V(  40, 0x261f,  68,  41, 0 ),
+  V(  41, 0x1f33,  69,  42, 0 ),
+  V(  42, 0x19a8,  70,  43, 0 ),
+  V(  43, 0x1518,  72,  44, 0 ),
+  V(  44, 0x1177,  73,  45, 0 ),
+  V(  45, 0x0e74,  74,  46, 0 ),
+  V(  46, 0x0bfb,  75,  47, 0 ),
+  V(  47, 0x09f8,  77,  48, 0 ),
+  V(  48, 0x0861,  78,  49, 0 ),
+  V(  49, 0x0706,  79,  50, 0 ),
+  V(  50, 0x05cd,  48,  51, 0 ),
+  V(  51, 0x04de,  50,  52, 0 ),
+  V(  52, 0x040f,  50,  53, 0 ),
+  V(  53, 0x0363,  51,  54, 0 ),
+  V(  54, 0x02d4,  52,  55, 0 ),
+  V(  55, 0x025c,  53,  56, 0 ),
+  V(  56, 0x01f8,  54,  57, 0 ),
+  V(  57, 0x01a4,  55,  58, 0 ),
+  V(  58, 0x0160,  56,  59, 0 ),
+  V(  59, 0x0125,  57,  60, 0 ),
+  V(  60, 0x00f6,  58,  61, 0 ),
+  V(  61, 0x00cb,  59,  62, 0 ),
+  V(  62, 0x00ab,  61,  63, 0 ),
+  V(  63, 0x008f,  61,  32, 0 ),
+  V(  64, 0x5b12,  65,  65, 1 ),
+  V(  65, 0x4d04,  80,  66, 0 ),
+  V(  66, 0x412c,  81,  67, 0 ),
+  V(  67, 0x37d8,  82,  68, 0 ),
+  V(  68, 0x2fe8,  83,  69, 0 ),
+  V(  69, 0x293c,  84,  70, 0 ),
+  V(  70, 0x2379,  86,  71, 0 ),
+  V(  71, 0x1edf,  87,  72, 0 ),
+  V(  72, 0x1aa9,  87,  73, 0 ),
+  V(  73, 0x174e,  72,  74, 0 ),
+  V(  74, 0x1424,  72,  75, 0 ),
+  V(  75, 0x119c,  74,  76, 0 ),
+  V(  76, 0x0f6b,  74,  77, 0 ),
+  V(  77, 0x0d51,  75,  78, 0 ),
+  V(  78, 0x0bb6,  77,  79, 0 ),
+  V(  79, 0x0a40,  77,  48, 0 ),
+  V(  80, 0x5832,  80,  81, 1 ),
+  V(  81, 0x4d1c,  88,  82, 0 ),
+  V(  82, 0x438e,  89,  83, 0 ),
+  V(  83, 0x3bdd,  90,  84, 0 ),
+  V(  84, 0x34ee,  91,  85, 0 ),
+  V(  85, 0x2eae,  92,  86, 0 ),
+  V(  86, 0x299a,  93,  87, 0 ),
+  V(  87, 0x2516,  86,  71, 0 ),
+  V(  88, 0x5570,  88,  89, 1 ),
+  V(  89, 0x4ca9,  95,  90, 0 ),
+  V(  90, 0x44d9,  96,  91, 0 ),
+  V(  91, 0x3e22,  97,  92, 0 ),
+  V(  92, 0x3824,  99,  93, 0 ),
+  V(  93, 0x32b4,  99,  94, 0 ),
+  V(  94, 0x2e17,  93,  86, 0 ),
+  V(  95, 0x56a8,  95,  96, 1 ),
+  V(  96, 0x4f46, 101,  97, 0 ),
+  V(  97, 0x47e5, 102,  98, 0 ),
+  V(  98, 0x41cf, 103,  99, 0 ),
+  V(  99, 0x3c3d, 104, 100, 0 ),
+  V( 100, 0x375e,  99,  93, 0 ),
+  V( 101, 0x5231, 105, 102, 0 ),
+  V( 102, 0x4c0f, 106, 103, 0 ),
+  V( 103, 0x4639, 107, 104, 0 ),
+  V( 104, 0x415e, 103,  99, 0 ),
+  V( 105, 0x5627, 105, 106, 1 ),
+  V( 106, 0x50e7, 108, 107, 0 ),
+  V( 107, 0x4b85, 109, 103, 0 ),
+  V( 108, 0x5597, 110, 109, 0 ),
+  V( 109, 0x504f, 111, 107, 0 ),
+  V( 110, 0x5a10, 110, 111, 1 ),
+  V( 111, 0x5522, 112, 109, 0 ),
+  V( 112, 0x59eb, 112, 111, 1 ),
+/*
+ * This last entry is used for fixed probability estimate of 0.5
+ * as recommended in Section 10.3 Table 5 of ITU-T Rec. T.851.
+ */
+  V( 113, 0x5a1d, 113, 113, 0 )
+};
diff --git a/jcapimin.c b/jcapimin.c
index 54fb8c5..20ba9e9 100644
--- a/jcapimin.c
+++ b/jcapimin.c
@@ -2,6 +2,7 @@
  * jcapimin.c
  *
  * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -63,14 +64,25 @@
 
   cinfo->comp_info = NULL;
 
-  for (i = 0; i < NUM_QUANT_TBLS; i++)
+  for (i = 0; i < NUM_QUANT_TBLS; i++) {
     cinfo->quant_tbl_ptrs[i] = NULL;
+#if JPEG_LIB_VERSION >= 70
+    cinfo->q_scale_factor[i] = 100;
+#endif
+  }
 
   for (i = 0; i < NUM_HUFF_TBLS; i++) {
     cinfo->dc_huff_tbl_ptrs[i] = NULL;
     cinfo->ac_huff_tbl_ptrs[i] = NULL;
   }
 
+#if JPEG_LIB_VERSION >= 80
+  /* Must do it here for emit_dqt in case jpeg_write_tables is used */
+  cinfo->block_size = DCTSIZE;
+  cinfo->natural_order = jpeg_natural_order;
+  cinfo->lim_Se = DCTSIZE2-1;
+#endif
+
   cinfo->script_space = NULL;
 
   cinfo->input_gamma = 1.0;	/* in case application forgets */
diff --git a/jcarith.c b/jcarith.c
new file mode 100644
index 0000000..a9ca1c3
--- /dev/null
+++ b/jcarith.c
@@ -0,0 +1,925 @@
+/*
+ * jcarith.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy encoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy encoder object for arithmetic encoding. */
+
+typedef struct {
+  struct jpeg_entropy_encoder pub; /* public fields */
+
+  INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
+  INT32 a;               /* A register, normalized size of coding interval */
+  INT32 sc;        /* counter for stacked 0xFF values which might overflow */
+  INT32 zc;          /* counter for pending 0x00 output values which might *
+                          * be discarded at the end ("Pacman" termination) */
+  int ct;  /* bit shift counter, determines when next byte will be written */
+  int buffer;                /* buffer for most recent output byte != 0xFF */
+
+  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+  int next_restart_num;		/* next restart number to write (0-7) */
+
+  /* Pointers to statistics areas (these workspaces have image lifespan) */
+  unsigned char * dc_stats[NUM_ARITH_TBLS];
+  unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+  /* Statistics bin for coding with fixed probability 0.5 */
+  unsigned char fixed_bin[4];
+} arith_entropy_encoder;
+
+typedef arith_entropy_encoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+/* NOTE: Uncomment the following #define if you want to use the
+ * given formula for calculating the AC conditioning parameter Kx
+ * for spectral selection progressive coding in section G.1.3.2
+ * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).
+ * Although the spec and P&M authors claim that this "has proven
+ * to give good results for 8 bit precision samples", I'm not
+ * convinced yet that this is really beneficial.
+ * Early tests gave only very marginal compression enhancements
+ * (a few - around 5 or so - bytes even for very large files),
+ * which would turn out rather negative if we'd suppress the
+ * DAC (Define Arithmetic Conditioning) marker segments for
+ * the default parameters in the future.
+ * Note that currently the marker writing module emits 12-byte
+ * DAC segments for a full-component scan in a color image.
+ * This is not worth worrying about IMHO. However, since the
+ * spec defines the default values to be used if the tables
+ * are omitted (unlike Huffman tables, which are required
+ * anyway), one might optimize this behaviour in the future,
+ * and then it would be disadvantageous to use custom tables if
+ * they don't provide sufficient gain to exceed the DAC size.
+ *
+ * On the other hand, I'd consider it as a reasonable result
+ * that the conditioning has no significant influence on the
+ * compression performance. This means that the basic
+ * statistical model is already rather stable.
+ *
+ * Thus, at the moment, we use the default conditioning values
+ * anyway, and do not use the custom formula.
+ *
+#define CALCULATE_SPECTRAL_CONDITIONING
+ */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS	int ishift_temp;
+#define IRIGHT_SHIFT(x,shft)  \
+	((ishift_temp = (x)) < 0 ? \
+	 (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+	 (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft)	((x) >> (shft))
+#endif
+
+
+LOCAL(void)
+emit_byte (int val, j_compress_ptr cinfo)
+/* Write next output byte; we do not support suspension in this module. */
+{
+  struct jpeg_destination_mgr * dest = cinfo->dest;
+
+  *dest->next_output_byte++ = (JOCTET) val;
+  if (--dest->free_in_buffer == 0)
+    if (! (*dest->empty_output_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+}
+
+
+/*
+ * Finish up at the end of an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass (j_compress_ptr cinfo)
+{
+  arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  INT32 temp;
+
+  /* Section D.1.8: Termination of encoding */
+
+  /* Find the e->c in the coding interval with the largest
+   * number of trailing zero bits */
+  if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)
+    e->c = temp + 0x8000L;
+  else
+    e->c = temp;
+  /* Send remaining bytes to output */
+  e->c <<= e->ct;
+  if (e->c & 0xF8000000L) {
+    /* One final overflow has to be handled */
+    if (e->buffer >= 0) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      emit_byte(e->buffer + 1, cinfo);
+      if (e->buffer + 1 == 0xFF)
+	emit_byte(0x00, cinfo);
+    }
+    e->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */
+    e->sc = 0;
+  } else {
+    if (e->buffer == 0)
+      ++e->zc;
+    else if (e->buffer >= 0) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      emit_byte(e->buffer, cinfo);
+    }
+    if (e->sc) {
+      if (e->zc)
+	do emit_byte(0x00, cinfo);
+	while (--e->zc);
+      do {
+	emit_byte(0xFF, cinfo);
+	emit_byte(0x00, cinfo);
+      } while (--e->sc);
+    }
+  }
+  /* Output final bytes only if they are not 0x00 */
+  if (e->c & 0x7FFF800L) {
+    if (e->zc)  /* output final pending zero bytes */
+      do emit_byte(0x00, cinfo);
+      while (--e->zc);
+    emit_byte((e->c >> 19) & 0xFF, cinfo);
+    if (((e->c >> 19) & 0xFF) == 0xFF)
+      emit_byte(0x00, cinfo);
+    if (e->c & 0x7F800L) {
+      emit_byte((e->c >> 11) & 0xFF, cinfo);
+      if (((e->c >> 11) & 0xFF) == 0xFF)
+	emit_byte(0x00, cinfo);
+    }
+  }
+}
+
+
+/*
+ * The core arithmetic encoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Parameter 'val' to be encoded may be 0 or 1 (binary decision).
+ *
+ * Note: I've added full "Pacman" termination support to the
+ * byte output routines, which is equivalent to the optional
+ * Discard_final_zeros procedure (Figure D.15) in the spec.
+ * Thus, we always produce the shortest possible output
+ * stream compliant to the spec (no trailing zero bytes,
+ * except for FF stuffing).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(void)
+arith_encode (j_compress_ptr cinfo, unsigned char *st, int val) 
+{
+  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  register unsigned char nl, nm;
+  register INT32 qe, temp;
+  register int sv;
+
+  /* Fetch values from our compact representation of Table D.2:
+   * Qe values and probability estimation state machine
+   */
+  sv = *st;
+  qe = jpeg_aritab[sv & 0x7F];	/* => Qe_Value */
+  nl = qe & 0xFF; qe >>= 8;	/* Next_Index_LPS + Switch_MPS */
+  nm = qe & 0xFF; qe >>= 8;	/* Next_Index_MPS */
+
+  /* Encode & estimation procedures per sections D.1.4 & D.1.5 */
+  e->a -= qe;
+  if (val != (sv >> 7)) {
+    /* Encode the less probable symbol */
+    if (e->a >= qe) {
+      /* If the interval size (qe) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency, otherwise code the LPS
+       * as usual: */
+      e->c += e->a;
+      e->a = qe;
+    }
+    *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+  } else {
+    /* Encode the more probable symbol */
+    if (e->a >= 0x8000L)
+      return;  /* A >= 0x8000 -> ready, no renormalization required */
+    if (e->a < qe) {
+      /* If the interval size (qe) for the less probable symbol (LPS)
+       * is larger than the interval size for the MPS, then exchange
+       * the two symbols for coding efficiency: */
+      e->c += e->a;
+      e->a = qe;
+    }
+    *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+  }
+
+  /* Renormalization & data output per section D.1.6 */
+  do {
+    e->a <<= 1;
+    e->c <<= 1;
+    if (--e->ct == 0) {
+      /* Another byte is ready for output */
+      temp = e->c >> 19;
+      if (temp > 0xFF) {
+	/* Handle overflow over all stacked 0xFF bytes */
+	if (e->buffer >= 0) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  emit_byte(e->buffer + 1, cinfo);
+	  if (e->buffer + 1 == 0xFF)
+	    emit_byte(0x00, cinfo);
+	}
+	e->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */
+	e->sc = 0;
+	/* Note: The 3 spacer bits in the C register guarantee
+	 * that the new buffer byte can't be 0xFF here
+	 * (see page 160 in the P&M JPEG book). */
+	e->buffer = temp & 0xFF;  /* new output byte, might overflow later */
+      } else if (temp == 0xFF) {
+	++e->sc;  /* stack 0xFF byte (which might overflow later) */
+      } else {
+	/* Output all stacked 0xFF bytes, they will not overflow any more */
+	if (e->buffer == 0)
+	  ++e->zc;
+	else if (e->buffer >= 0) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  emit_byte(e->buffer, cinfo);
+	}
+	if (e->sc) {
+	  if (e->zc)
+	    do emit_byte(0x00, cinfo);
+	    while (--e->zc);
+	  do {
+	    emit_byte(0xFF, cinfo);
+	    emit_byte(0x00, cinfo);
+	  } while (--e->sc);
+	}
+	e->buffer = temp & 0xFF;  /* new output byte (can still overflow) */
+      }
+      e->c &= 0x7FFFFL;
+      e->ct += 8;
+    }
+  } while (e->a < 0x8000L);
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(void)
+emit_restart (j_compress_ptr cinfo, int restart_num)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci;
+  jpeg_component_info * compptr;
+
+  finish_pass(cinfo);
+
+  emit_byte(0xFF, cinfo);
+  emit_byte(JPEG_RST0 + restart_num, cinfo);
+
+  /* Re-initialize statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      /* Reset DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    /* AC needs no table when not present */
+    if (cinfo->progressive_mode == 0 || cinfo->Se) {
+      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+    }
+  }
+
+  /* Reset arithmetic encoding variables */
+  entropy->c = 0;
+  entropy->a = 0x10000L;
+  entropy->sc = 0;
+  entropy->zc = 0;
+  entropy->ct = 11;
+  entropy->buffer = -1;  /* empty */
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl;
+  int v, v2, m;
+  ISHIFT_TEMPS
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+    /* Compute the DC value after the required point transform by Al.
+     * This is simply an arithmetic right shift.
+     */
+    m = IRIGHT_SHIFT((int) ((*block)[0]), cinfo->Al);
+
+    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.4: Encode_DC_DIFF */
+    if ((v = m - entropy->last_dc_val[ci]) == 0) {
+      arith_encode(cinfo, st, 0);
+      entropy->dc_context[ci] = 0;	/* zero diff category */
+    } else {
+      entropy->last_dc_val[ci] = m;
+      arith_encode(cinfo, st, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, st + 1, 0);	/* Table F.4: SS = S0 + 1 */
+	st += 2;			/* Table F.4: SP = S0 + 2 */
+	entropy->dc_context[ci] = 4;	/* small positive diff category */
+      } else {
+	v = -v;
+	arith_encode(cinfo, st + 1, 1);	/* Table F.4: SS = S0 + 1 */
+	st += 3;			/* Table F.4: SN = S0 + 3 */
+	entropy->dc_context[ci] = 8;	/* small negative diff category */
+      }
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;	/* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] += 8;	/* large diff category */
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, k, ke;
+  int v, v2, m;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+  /* Establish EOB (end-of-block) index */
+  for (ke = cinfo->Se; ke > 0; ke--)
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value.
+     */
+    if ((v = (*block)[jpeg_natural_order[ke]]) >= 0) {
+      if (v >>= cinfo->Al) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Al) break;
+    }
+
+  /* Figure F.5: Encode_AC_Coefficients */
+  for (k = cinfo->Ss; k <= ke; k++) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    arith_encode(cinfo, st, 0);		/* EOB decision */
+    for (;;) {
+      if ((v = (*block)[jpeg_natural_order[k]]) >= 0) {
+	if (v >>= cinfo->Al) {
+	  arith_encode(cinfo, st + 1, 1);
+	  arith_encode(cinfo, entropy->fixed_bin, 0);
+	  break;
+	}
+      } else {
+	v = -v;
+	if (v >>= cinfo->Al) {
+	  arith_encode(cinfo, st + 1, 1);
+	  arith_encode(cinfo, entropy->fixed_bin, 1);
+	  break;
+	}
+      }
+      arith_encode(cinfo, st + 1, 0); st += 3; k++;
+    }
+    st += 2;
+    /* Figure F.8: Encoding the magnitude category of v */
+    m = 0;
+    if (v -= 1) {
+      arith_encode(cinfo, st, 1);
+      m = 1;
+      v2 = v;
+      if (v2 >>= 1) {
+	arith_encode(cinfo, st, 1);
+	m <<= 1;
+	st = entropy->ac_stats[tbl] +
+	     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+    }
+    arith_encode(cinfo, st, 0);
+    /* Figure F.9: Encoding the magnitude bit pattern of v */
+    st += 14;
+    while (m >>= 1)
+      arith_encode(cinfo, st, (m & v) ? 1 : 0);
+  }
+  /* Encode EOB decision only if k <= cinfo->Se */
+  if (k <= cinfo->Se) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    arith_encode(cinfo, st, 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  unsigned char *st;
+  int Al, blkn;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  st = entropy->fixed_bin;	/* use fixed probability estimation */
+  Al = cinfo->Al;
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* We simply emit the Al'th bit of the DC coefficient value. */
+    arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, k, ke, kex;
+  int v;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  /* Encode the MCU data block */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Section G.1.3.3: Encoding of AC coefficients */
+
+  /* Establish EOB (end-of-block) index */
+  for (ke = cinfo->Se; ke > 0; ke--)
+    /* We must apply the point transform by Al.  For AC coefficients this
+     * is an integer division with rounding towards 0.  To do this portably
+     * in C, we shift after obtaining the absolute value.
+     */
+    if ((v = (*block)[jpeg_natural_order[ke]]) >= 0) {
+      if (v >>= cinfo->Al) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Al) break;
+    }
+
+  /* Establish EOBx (previous stage end-of-block) index */
+  for (kex = ke; kex > 0; kex--)
+    if ((v = (*block)[jpeg_natural_order[kex]]) >= 0) {
+      if (v >>= cinfo->Ah) break;
+    } else {
+      v = -v;
+      if (v >>= cinfo->Ah) break;
+    }
+
+  /* Figure G.10: Encode_AC_Coefficients_SA */
+  for (k = cinfo->Ss; k <= ke; k++) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    if (k > kex)
+      arith_encode(cinfo, st, 0);	/* EOB decision */
+    for (;;) {
+      if ((v = (*block)[jpeg_natural_order[k]]) >= 0) {
+	if (v >>= cinfo->Al) {
+	  if (v >> 1)			/* previously nonzero coef */
+	    arith_encode(cinfo, st + 2, (v & 1));
+	  else {			/* newly nonzero coef */
+	    arith_encode(cinfo, st + 1, 1);
+	    arith_encode(cinfo, entropy->fixed_bin, 0);
+	  }
+	  break;
+	}
+      } else {
+	v = -v;
+	if (v >>= cinfo->Al) {
+	  if (v >> 1)			/* previously nonzero coef */
+	    arith_encode(cinfo, st + 2, (v & 1));
+	  else {			/* newly nonzero coef */
+	    arith_encode(cinfo, st + 1, 1);
+	    arith_encode(cinfo, entropy->fixed_bin, 1);
+	  }
+	  break;
+	}
+      }
+      arith_encode(cinfo, st + 1, 0); st += 3; k++;
+    }
+  }
+  /* Encode EOB decision only if k <= cinfo->Se */
+  if (k <= cinfo->Se) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    arith_encode(cinfo, st, 1);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  jpeg_component_info * compptr;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl, k, ke;
+  int v, v2, m;
+
+  /* Emit restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0) {
+      emit_restart(cinfo, entropy->next_restart_num);
+      entropy->restarts_to_go = cinfo->restart_interval;
+      entropy->next_restart_num++;
+      entropy->next_restart_num &= 7;
+    }
+    entropy->restarts_to_go--;
+  }
+
+  /* Encode the MCU data blocks */
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+
+    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+    tbl = compptr->dc_tbl_no;
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.4: Encode_DC_DIFF */
+    if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {
+      arith_encode(cinfo, st, 0);
+      entropy->dc_context[ci] = 0;	/* zero diff category */
+    } else {
+      entropy->last_dc_val[ci] = (*block)[0];
+      arith_encode(cinfo, st, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, st + 1, 0);	/* Table F.4: SS = S0 + 1 */
+	st += 2;			/* Table F.4: SP = S0 + 2 */
+	entropy->dc_context[ci] = 4;	/* small positive diff category */
+      } else {
+	v = -v;
+	arith_encode(cinfo, st + 1, 1);	/* Table F.4: SS = S0 + 1 */
+	st += 3;			/* Table F.4: SN = S0 + 3 */
+	entropy->dc_context[ci] = 8;	/* small negative diff category */
+      }
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+	while (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st += 1;
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;	/* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] += 8;	/* large diff category */
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+
+    /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+    tbl = compptr->ac_tbl_no;
+
+    /* Establish EOB (end-of-block) index */
+    for (ke = DCTSIZE2 - 1; ke > 0; ke--)
+      if ((*block)[jpeg_natural_order[ke]]) break;
+
+    /* Figure F.5: Encode_AC_Coefficients */
+    for (k = 1; k <= ke; k++) {
+      st = entropy->ac_stats[tbl] + 3 * (k - 1);
+      arith_encode(cinfo, st, 0);	/* EOB decision */
+      while ((v = (*block)[jpeg_natural_order[k]]) == 0) {
+	arith_encode(cinfo, st + 1, 0); st += 3; k++;
+      }
+      arith_encode(cinfo, st + 1, 1);
+      /* Figure F.6: Encoding nonzero value v */
+      /* Figure F.7: Encoding the sign of v */
+      if (v > 0) {
+	arith_encode(cinfo, entropy->fixed_bin, 0);
+      } else {
+	v = -v;
+	arith_encode(cinfo, entropy->fixed_bin, 1);
+      }
+      st += 2;
+      /* Figure F.8: Encoding the magnitude category of v */
+      m = 0;
+      if (v -= 1) {
+	arith_encode(cinfo, st, 1);
+	m = 1;
+	v2 = v;
+	if (v2 >>= 1) {
+	  arith_encode(cinfo, st, 1);
+	  m <<= 1;
+	  st = entropy->ac_stats[tbl] +
+	       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	  while (v2 >>= 1) {
+	    arith_encode(cinfo, st, 1);
+	    m <<= 1;
+	    st += 1;
+	  }
+	}
+      }
+      arith_encode(cinfo, st, 0);
+      /* Figure F.9: Encoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	arith_encode(cinfo, st, (m & v) ? 1 : 0);
+    }
+    /* Encode EOB decision only if k <= DCTSIZE2 - 1 */
+    if (k <= DCTSIZE2 - 1) {
+      st = entropy->ac_stats[tbl] + 3 * (k - 1);
+      arith_encode(cinfo, st, 1);
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_compress_ptr cinfo, boolean gather_statistics)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+
+  if (gather_statistics)
+    /* Make sure to avoid that in the master control logic!
+     * We are fully adaptive here and need no extra
+     * statistics gathering pass!
+     */
+    ERREXIT(cinfo, JERR_NOT_COMPILED);
+
+  /* We assume jcmaster.c already validated the progressive scan parameters. */
+
+  /* Select execution routines */
+  if (cinfo->progressive_mode) {
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_first;
+      else
+	entropy->pub.encode_mcu = encode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.encode_mcu = encode_mcu_DC_refine;
+      else
+	entropy->pub.encode_mcu = encode_mcu_AC_refine;
+    }
+  } else
+    entropy->pub.encode_mcu = encode_mcu;
+
+  /* Allocate & initialize requested statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* DC needs no table for refinement scan */
+    if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      tbl = compptr->dc_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->dc_stats[tbl] == NULL)
+	entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      /* Initialize DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    /* AC needs no table when not present */
+    if (cinfo->progressive_mode == 0 || cinfo->Se) {
+      tbl = compptr->ac_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->ac_stats[tbl] == NULL)
+	entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+#ifdef CALCULATE_SPECTRAL_CONDITIONING
+      if (cinfo->progressive_mode)
+	/* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
+	cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
+#endif
+    }
+  }
+
+  /* Initialize arithmetic encoding variables */
+  entropy->c = 0;
+  entropy->a = 0x10000L;
+  entropy->sc = 0;
+  entropy->zc = 0;
+  entropy->ct = 11;
+  entropy->buffer = -1;  /* empty */
+
+  /* Initialize restart stuff */
+  entropy->restarts_to_go = cinfo->restart_interval;
+  entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_arith_encoder (j_compress_ptr cinfo)
+{
+  arith_entropy_ptr entropy;
+  int i;
+
+  entropy = (arith_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(arith_entropy_encoder));
+  cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+  entropy->pub.start_pass = start_pass;
+  entropy->pub.finish_pass = finish_pass;
+
+  /* Mark tables unallocated */
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    entropy->dc_stats[i] = NULL;
+    entropy->ac_stats[i] = NULL;
+  }
+
+  /* Initialize index for fixed probability estimation */
+  entropy->fixed_bin[0] = 113;
+}
diff --git a/jccolor.c b/jccolor.c
index 05da604..b374c8b 100644
--- a/jccolor.c
+++ b/jccolor.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright 2009 D. R. Commander
+ * Copyright 2009-2011 D. R. Commander
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -83,7 +83,7 @@
 
 #if BITS_IN_JSAMPLE == 8
 
-const unsigned char red_lut[256] = {
+static const unsigned char red_lut[256] = {
   0 , 0 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3 , 4 , 4 , 4 , 4 ,
   5 , 5 , 5 , 6 , 6 , 6 , 7 , 7 , 7 , 7 , 8 , 8 , 8 , 9 , 9 , 9 ,
   10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14,
@@ -102,7 +102,7 @@
   72, 72, 72, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 76, 76, 76
 };
 
-const unsigned char green_lut[256] = {
+static const unsigned char green_lut[256] = {
   0  , 1  , 1  , 2  , 2  , 3  , 4  , 4  , 5  , 5  , 6  , 6  ,
   7  , 8  , 8  , 9  , 9  , 10 , 11 , 11 , 12 , 12 , 13 , 14 ,
   14 , 15 , 15 , 16 , 16 , 17 , 18 , 18 , 19 , 19 , 20 , 21 ,
@@ -127,7 +127,7 @@
   148, 149, 149, 150
 };
 
-const unsigned char blue_lut[256] = {
+static const unsigned char blue_lut[256] = {
   0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 ,
   2 , 2 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 4 ,
   4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 ,
@@ -258,14 +258,13 @@
 		  JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
 		  JDIMENSION output_row, int num_rows)
 {
-  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
   #if BITS_IN_JSAMPLE != 8
+  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
   register INT32 * ctab = cconvert->rgb_ycc_tab;
   #endif
   register JSAMPROW inptr;
   register JSAMPROW outptr;
   JSAMPLE *maxoutptr;
-  register JDIMENSION col;
   JDIMENSION num_cols = cinfo->image_width;
   int rindex = rgb_red[cinfo->in_color_space];
   int gindex = rgb_green[cinfo->in_color_space];
diff --git a/jcdctmgr.c b/jcdctmgr.c
index 711f9da..12f8872 100644
--- a/jcdctmgr.c
+++ b/jcdctmgr.c
@@ -182,7 +182,7 @@
     /* fq will be one bit too large to fit in DCTELEM, so adjust */
     fq >>= 1;
     r--;
-  } else if (fr <= (divisor / 2)) { /* fractional part is < 0.5 */
+  } else if (fr <= (divisor / 2U)) { /* fractional part is < 0.5 */
     c++;
   } else { /* fractional part is > 0.5 */
     fq++;
diff --git a/jchuff.c b/jchuff.c
index b05c8e7..8a46b98 100644
--- a/jchuff.c
+++ b/jchuff.c
@@ -36,7 +36,7 @@
 #include <limits.h>
 
 static unsigned char jpeg_first_bit_table[65536];
-int jpeg_first_bit_table_init=0;
+static int jpeg_first_bit_table_init=0;
 
 #ifndef min
  #define min(a,b) ((a)<(b)?(a):(b))
@@ -423,8 +423,6 @@
   CHECKBUF15()                                \
  }
 
-int _max=0;
-
 #if __WORDSIZE==64 || defined(_WIN64)
 
 #define DUMP_VALUE(ht, codevalue, t, nbits) { \
diff --git a/jcinit.c b/jcinit.c
index 5efffe3..de0ade2 100644
--- a/jcinit.c
+++ b/jcinit.c
@@ -42,7 +42,11 @@
   jinit_forward_dct(cinfo);
   /* Entropy encoding: either Huffman or arithmetic coding. */
   if (cinfo->arith_code) {
+#ifdef C_ARITH_CODING_SUPPORTED
+    jinit_arith_encoder(cinfo);
+#else
     ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
   } else {
     if (cinfo->progressive_mode) {
 #ifdef C_PROGRESSIVE_SUPPORTED
diff --git a/jcmainct.c b/jcmainct.c
index e0279a7..bd0051a 100644
--- a/jcmainct.c
+++ b/jcmainct.c
@@ -68,32 +68,32 @@
 METHODDEF(void)
 start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
 
   /* Do nothing in raw-data mode. */
   if (cinfo->raw_data_in)
     return;
 
-  main->cur_iMCU_row = 0;	/* initialize counters */
-  main->rowgroup_ctr = 0;
-  main->suspended = FALSE;
-  main->pass_mode = pass_mode;	/* save mode for use by process_data */
+  main_ptr->cur_iMCU_row = 0;	/* initialize counters */
+  main_ptr->rowgroup_ctr = 0;
+  main_ptr->suspended = FALSE;
+  main_ptr->pass_mode = pass_mode;	/* save mode for use by process_data */
 
   switch (pass_mode) {
   case JBUF_PASS_THRU:
 #ifdef FULL_MAIN_BUFFER_SUPPORTED
-    if (main->whole_image[0] != NULL)
+    if (main_ptr->whole_image[0] != NULL)
       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
 #endif
-    main->pub.process_data = process_data_simple_main;
+    main_ptr->pub.process_data = process_data_simple_main;
     break;
 #ifdef FULL_MAIN_BUFFER_SUPPORTED
   case JBUF_SAVE_SOURCE:
   case JBUF_CRANK_DEST:
   case JBUF_SAVE_AND_PASS:
-    if (main->whole_image[0] == NULL)
+    if (main_ptr->whole_image[0] == NULL)
       ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
-    main->pub.process_data = process_data_buffer_main;
+    main_ptr->pub.process_data = process_data_buffer_main;
     break;
 #endif
   default:
@@ -114,46 +114,46 @@
 			  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
 			  JDIMENSION in_rows_avail)
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
 
-  while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+  while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
     /* Read input data if we haven't filled the main buffer yet */
-    if (main->rowgroup_ctr < DCTSIZE)
+    if (main_ptr->rowgroup_ctr < DCTSIZE)
       (*cinfo->prep->pre_process_data) (cinfo,
 					input_buf, in_row_ctr, in_rows_avail,
-					main->buffer, &main->rowgroup_ctr,
+					main_ptr->buffer, &main_ptr->rowgroup_ctr,
 					(JDIMENSION) DCTSIZE);
 
     /* If we don't have a full iMCU row buffered, return to application for
      * more data.  Note that preprocessor will always pad to fill the iMCU row
      * at the bottom of the image.
      */
-    if (main->rowgroup_ctr != DCTSIZE)
+    if (main_ptr->rowgroup_ctr != DCTSIZE)
       return;
 
     /* Send the completed row to the compressor */
-    if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+    if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
       /* If compressor did not consume the whole row, then we must need to
        * suspend processing and return to the application.  In this situation
        * we pretend we didn't yet consume the last input row; otherwise, if
        * it happened to be the last row of the image, the application would
        * think we were done.
        */
-      if (! main->suspended) {
+      if (! main_ptr->suspended) {
 	(*in_row_ctr)--;
-	main->suspended = TRUE;
+	main_ptr->suspended = TRUE;
       }
       return;
     }
     /* We did finish the row.  Undo our little suspension hack if a previous
      * call suspended; then mark the main buffer empty.
      */
-    if (main->suspended) {
+    if (main_ptr->suspended) {
       (*in_row_ctr)++;
-      main->suspended = FALSE;
+      main_ptr->suspended = FALSE;
     }
-    main->rowgroup_ctr = 0;
-    main->cur_iMCU_row++;
+    main_ptr->rowgroup_ctr = 0;
+    main_ptr->cur_iMCU_row++;
   }
 }
 
@@ -173,22 +173,22 @@
   my_main_ptr main = (my_main_ptr) cinfo->main;
   int ci;
   jpeg_component_info *compptr;
-  boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
+  boolean writing = (main_ptr->pass_mode != JBUF_CRANK_DEST);
 
-  while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+  while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
     /* Realign the virtual buffers if at the start of an iMCU row. */
-    if (main->rowgroup_ctr == 0) {
+    if (main_ptr->rowgroup_ctr == 0) {
       for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
 	   ci++, compptr++) {
-	main->buffer[ci] = (*cinfo->mem->access_virt_sarray)
-	  ((j_common_ptr) cinfo, main->whole_image[ci],
-	   main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
+	main_ptr->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+	  ((j_common_ptr) cinfo, main_ptr->whole_image[ci],
+	   main_ptr->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
 	   (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
       }
       /* In a read pass, pretend we just read some source data. */
       if (! writing) {
 	*in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
-	main->rowgroup_ctr = DCTSIZE;
+	main_ptr->rowgroup_ctr = DCTSIZE;
       }
     }
 
@@ -197,40 +197,40 @@
     if (writing) {
       (*cinfo->prep->pre_process_data) (cinfo,
 					input_buf, in_row_ctr, in_rows_avail,
-					main->buffer, &main->rowgroup_ctr,
+					main_ptr->buffer, &main_ptr->rowgroup_ctr,
 					(JDIMENSION) DCTSIZE);
       /* Return to application if we need more data to fill the iMCU row. */
-      if (main->rowgroup_ctr < DCTSIZE)
+      if (main_ptr->rowgroup_ctr < DCTSIZE)
 	return;
     }
 
     /* Emit data, unless this is a sink-only pass. */
-    if (main->pass_mode != JBUF_SAVE_SOURCE) {
-      if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+    if (main_ptr->pass_mode != JBUF_SAVE_SOURCE) {
+      if (! (*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
 	/* If compressor did not consume the whole row, then we must need to
 	 * suspend processing and return to the application.  In this situation
 	 * we pretend we didn't yet consume the last input row; otherwise, if
 	 * it happened to be the last row of the image, the application would
 	 * think we were done.
 	 */
-	if (! main->suspended) {
+	if (! main_ptr->suspended) {
 	  (*in_row_ctr)--;
-	  main->suspended = TRUE;
+	  main_ptr->suspended = TRUE;
 	}
 	return;
       }
       /* We did finish the row.  Undo our little suspension hack if a previous
        * call suspended; then mark the main buffer empty.
        */
-      if (main->suspended) {
+      if (main_ptr->suspended) {
 	(*in_row_ctr)++;
-	main->suspended = FALSE;
+	main_ptr->suspended = FALSE;
       }
     }
 
     /* If get here, we are done with this iMCU row.  Mark buffer empty. */
-    main->rowgroup_ctr = 0;
-    main->cur_iMCU_row++;
+    main_ptr->rowgroup_ctr = 0;
+    main_ptr->cur_iMCU_row++;
   }
 }
 
@@ -244,15 +244,15 @@
 GLOBAL(void)
 jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
 {
-  my_main_ptr main;
+  my_main_ptr main_ptr;
   int ci;
   jpeg_component_info *compptr;
 
-  main = (my_main_ptr)
+  main_ptr = (my_main_ptr)
     (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
 				SIZEOF(my_main_controller));
-  cinfo->main = (struct jpeg_c_main_controller *) main;
-  main->pub.start_pass = start_pass_main;
+  cinfo->main = (struct jpeg_c_main_controller *) main_ptr;
+  main_ptr->pub.start_pass = start_pass_main;
 
   /* We don't need to create a buffer in raw-data mode. */
   if (cinfo->raw_data_in)
@@ -267,7 +267,7 @@
     /* Note we pad the bottom to a multiple of the iMCU height */
     for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
 	 ci++, compptr++) {
-      main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+      main_ptr->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
 	((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
 	 compptr->width_in_blocks * DCTSIZE,
 	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
@@ -279,12 +279,12 @@
 #endif
   } else {
 #ifdef FULL_MAIN_BUFFER_SUPPORTED
-    main->whole_image[0] = NULL; /* flag for no virtual arrays */
+    main_ptr->whole_image[0] = NULL; /* flag for no virtual arrays */
 #endif
     /* Allocate a strip buffer for each component */
     for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
 	 ci++, compptr++) {
-      main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+      main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
 	((j_common_ptr) cinfo, JPOOL_IMAGE,
 	 compptr->width_in_blocks * DCTSIZE,
 	 (JDIMENSION) (compptr->v_samp_factor * DCTSIZE));
diff --git a/jcmarker.c b/jcmarker.c
index 3d1e6c6..b1c1e45 100644
--- a/jcmarker.c
+++ b/jcmarker.c
@@ -2,6 +2,7 @@
  * jcmarker.c
  *
  * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -11,6 +12,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 typedef enum {			/* JPEG marker codes */
@@ -285,13 +287,13 @@
   emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
 
   /* Make sure image isn't bigger than SOF field can handle */
-  if ((long) cinfo->image_height > 65535L ||
-      (long) cinfo->image_width > 65535L)
+  if ((long) cinfo->_jpeg_height > 65535L ||
+      (long) cinfo->_jpeg_width > 65535L)
     ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
 
   emit_byte(cinfo, cinfo->data_precision);
-  emit_2bytes(cinfo, (int) cinfo->image_height);
-  emit_2bytes(cinfo, (int) cinfo->image_width);
+  emit_2bytes(cinfo, (int) cinfo->_jpeg_height);
+  emit_2bytes(cinfo, (int) cinfo->_jpeg_width);
 
   emit_byte(cinfo, cinfo->num_components);
 
diff --git a/jcmaster.c b/jcmaster.c
index aab4020..3ca346c 100644
--- a/jcmaster.c
+++ b/jcmaster.c
@@ -2,6 +2,8 @@
  * jcmaster.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -14,6 +16,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 /* Private state */
@@ -42,8 +45,28 @@
  * Support routines that do various essential calculations.
  */
 
+#if JPEG_LIB_VERSION >= 70
+/*
+ * Compute JPEG image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+  /* Hardwire it to "no scaling" */
+  cinfo->jpeg_width = cinfo->image_width;
+  cinfo->jpeg_height = cinfo->image_height;
+  cinfo->min_DCT_h_scaled_size = DCTSIZE;
+  cinfo->min_DCT_v_scaled_size = DCTSIZE;
+}
+#endif
+
+
 LOCAL(void)
-initial_setup (j_compress_ptr cinfo)
+initial_setup (j_compress_ptr cinfo, boolean transcode_only)
 /* Do computations that are needed before master selection phase */
 {
   int ci;
@@ -51,14 +74,21 @@
   long samplesperrow;
   JDIMENSION jd_samplesperrow;
 
+#if JPEG_LIB_VERSION >= 70
+#if JPEG_LIB_VERSION >= 80
+  if (!transcode_only)
+#endif
+    jpeg_calc_jpeg_dimensions(cinfo);
+#endif
+
   /* Sanity check on image dimensions */
-  if (cinfo->image_height <= 0 || cinfo->image_width <= 0
+  if (cinfo->_jpeg_height <= 0 || cinfo->_jpeg_width <= 0
       || cinfo->num_components <= 0 || cinfo->input_components <= 0)
     ERREXIT(cinfo, JERR_EMPTY_IMAGE);
 
   /* Make sure image isn't bigger than I can handle */
-  if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
-      (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+  if ((long) cinfo->_jpeg_height > (long) JPEG_MAX_DIMENSION ||
+      (long) cinfo->_jpeg_width > (long) JPEG_MAX_DIMENSION)
     ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
 
   /* Width of an input scanline must be representable as JDIMENSION. */
@@ -96,20 +126,24 @@
     /* Fill in the correct component_index value; don't rely on application */
     compptr->component_index = ci;
     /* For compression, we never do DCT scaling. */
+#if JPEG_LIB_VERSION >= 70
+    compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+#else
     compptr->DCT_scaled_size = DCTSIZE;
+#endif
     /* Size in DCT blocks */
     compptr->width_in_blocks = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+      jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
 		    (long) (cinfo->max_h_samp_factor * DCTSIZE));
     compptr->height_in_blocks = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+      jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
 		    (long) (cinfo->max_v_samp_factor * DCTSIZE));
     /* Size in samples */
     compptr->downsampled_width = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+      jdiv_round_up((long) cinfo->_jpeg_width * (long) compptr->h_samp_factor,
 		    (long) cinfo->max_h_samp_factor);
     compptr->downsampled_height = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+      jdiv_round_up((long) cinfo->_jpeg_height * (long) compptr->v_samp_factor,
 		    (long) cinfo->max_v_samp_factor);
     /* Mark component needed (this flag isn't actually used for compression) */
     compptr->component_needed = TRUE;
@@ -119,7 +153,7 @@
    * main controller will call coefficient controller).
    */
   cinfo->total_iMCU_rows = (JDIMENSION)
-    jdiv_round_up((long) cinfo->image_height,
+    jdiv_round_up((long) cinfo->_jpeg_height,
 		  (long) (cinfo->max_v_samp_factor*DCTSIZE));
 }
 
@@ -347,10 +381,10 @@
     
     /* Overall image size in MCUs */
     cinfo->MCUs_per_row = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_width,
+      jdiv_round_up((long) cinfo->_jpeg_width,
 		    (long) (cinfo->max_h_samp_factor*DCTSIZE));
     cinfo->MCU_rows_in_scan = (JDIMENSION)
-      jdiv_round_up((long) cinfo->image_height,
+      jdiv_round_up((long) cinfo->_jpeg_height,
 		    (long) (cinfo->max_v_samp_factor*DCTSIZE));
     
     cinfo->blocks_in_MCU = 0;
@@ -554,7 +588,7 @@
   master->pub.is_last_pass = FALSE;
 
   /* Validate parameters, determine derived values */
-  initial_setup(cinfo);
+  initial_setup(cinfo, transcode_only);
 
   if (cinfo->scan_info != NULL) {
 #ifdef C_MULTISCAN_FILES_SUPPORTED
diff --git a/jconfig.h.in b/jconfig.h.in
index 4e5e80e..670afab 100644
--- a/jconfig.h.in
+++ b/jconfig.h.in
@@ -1,3 +1,14 @@
+/* Version ID for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
+ */
+#define JPEG_LIB_VERSION  62	/* Version 6b */
+
+/* Support arithmetic encoding */
+#undef C_ARITH_CODING_SUPPORTED
+
+/* Support arithmetic decoding */
+#undef D_ARITH_CODING_SUPPORTED
+
 /* Define if your compiler supports prototypes */
 #undef HAVE_PROTOTYPES
 
diff --git a/jconfig.doc b/jconfig.txt
similarity index 93%
rename from jconfig.doc
rename to jconfig.txt
index c18d1c0..b96d312 100644
--- a/jconfig.doc
+++ b/jconfig.txt
@@ -1,5 +1,5 @@
 /*
- * jconfig.doc
+ * jconfig.txt
  *
  * Copyright (C) 1991-1994, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
@@ -24,7 +24,7 @@
  */
 
 /* Does your compiler support function prototypes?
- * (If not, you also need to use ansi2knr, see install.doc)
+ * (If not, you also need to use ansi2knr, see install.txt)
  */
 #define HAVE_PROTOTYPES
 
@@ -91,6 +91,15 @@
  */
 #undef INCOMPLETE_TYPES_BROKEN
 
+/* Define "boolean" as unsigned char, not int, on Windows systems.
+ */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__		/* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN		/* prevent jmorecfg.h from redefining it */
+#endif
+
 
 /*
  * The following options affect code selection within the JPEG library,
diff --git a/jcparam.c b/jcparam.c
index a1d49d9..27b5a03 100644
--- a/jcparam.c
+++ b/jcparam.c
@@ -2,7 +2,8 @@
  * jcparam.c
  *
  * Copyright (C) 1991-1998, Thomas G. Lane.
- * Copyright (C) 2009, D. R. Commander.
+ * Modified 2003-2008 by Guido Vollbeding.
+ * Copyright (C) 2009-2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -61,6 +62,49 @@
 }
 
 
+/* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+  16,  11,  10,  16,  24,  40,  51,  61,
+  12,  12,  14,  19,  26,  58,  60,  55,
+  14,  13,  16,  24,  40,  57,  69,  56,
+  14,  17,  22,  29,  51,  87,  80,  62,
+  18,  22,  37,  56,  68, 109, 103,  77,
+  24,  35,  55,  64,  81, 104, 113,  92,
+  49,  64,  78,  87, 103, 121, 120, 101,
+  72,  92,  95,  98, 112, 100, 103,  99
+};
+static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+  17,  18,  24,  47,  99,  99,  99,  99,
+  18,  21,  26,  66,  99,  99,  99,  99,
+  24,  26,  56,  99,  99,  99,  99,  99,
+  47,  66,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99
+};
+
+
+#if JPEG_LIB_VERSION >= 70
+GLOBAL(void)
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and straight percentage-scaling quality scales.
+ * This entry point allows different scalings for luminance and chrominance.
+ */
+{
+  /* Set up two quantization tables using the specified scaling */
+  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+		       cinfo->q_scale_factor[0], force_baseline);
+  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+		       cinfo->q_scale_factor[1], force_baseline);
+}
+#endif
+
+
 GLOBAL(void)
 jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
 			 boolean force_baseline)
@@ -70,31 +114,6 @@
  * applications that insist on a linear percentage scaling.
  */
 {
-  /* These are the sample quantization tables given in JPEG spec section K.1.
-   * The spec says that the values given produce "good" quality, and
-   * when divided by 2, "very good" quality.
-   */
-  static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
-    16,  11,  10,  16,  24,  40,  51,  61,
-    12,  12,  14,  19,  26,  58,  60,  55,
-    14,  13,  16,  24,  40,  57,  69,  56,
-    14,  17,  22,  29,  51,  87,  80,  62,
-    18,  22,  37,  56,  68, 109, 103,  77,
-    24,  35,  55,  64,  81, 104, 113,  92,
-    49,  64,  78,  87, 103, 121, 120, 101,
-    72,  92,  95,  98, 112, 100, 103,  99
-  };
-  static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
-    17,  18,  24,  47,  99,  99,  99,  99,
-    18,  21,  26,  66,  99,  99,  99,  99,
-    24,  26,  56,  99,  99,  99,  99,  99,
-    47,  66,  99,  99,  99,  99,  99,  99,
-    99,  99,  99,  99,  99,  99,  99,  99,
-    99,  99,  99,  99,  99,  99,  99,  99,
-    99,  99,  99,  99,  99,  99,  99,  99,
-    99,  99,  99,  99,  99,  99,  99,  99
-  };
-
   /* Set up two quantization tables using the specified scaling */
   jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
 		       scale_factor, force_baseline);
@@ -285,6 +304,10 @@
 
   /* Initialize everything not dependent on the color space */
 
+#if JPEG_LIB_VERSION >= 70
+  cinfo->scale_num = 1;		/* 1:1 scaling */
+  cinfo->scale_denom = 1;
+#endif
   cinfo->data_precision = BITS_IN_JSAMPLE;
   /* Set up two quantization tables using default quality of 75 */
   jpeg_set_quality(cinfo, 75, TRUE);
@@ -321,6 +344,11 @@
   /* By default, use the simpler non-cosited sampling alignment */
   cinfo->CCIR601_sampling = FALSE;
 
+#if JPEG_LIB_VERSION >= 70
+  /* By default, apply fancy downsampling */
+  cinfo->do_fancy_downsampling = TRUE;
+#endif
+
   /* No input smoothing */
   cinfo->smoothing_factor = 0;
 
diff --git a/jctrans.c b/jctrans.c
index 0e6d707..916e872 100644
--- a/jctrans.c
+++ b/jctrans.c
@@ -2,6 +2,7 @@
  * jctrans.c
  *
  * Copyright (C) 1995-1998, Thomas G. Lane.
+ * Modified 2000-2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -76,6 +77,12 @@
   dstinfo->image_height = srcinfo->image_height;
   dstinfo->input_components = srcinfo->num_components;
   dstinfo->in_color_space = srcinfo->jpeg_color_space;
+#if JPEG_LIB_VERSION >= 70
+  dstinfo->jpeg_width = srcinfo->output_width;
+  dstinfo->jpeg_height = srcinfo->output_height;
+  dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;
+  dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;
+#endif
   /* Initialize all parameters to default values */
   jpeg_set_defaults(dstinfo);
   /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
@@ -167,7 +174,11 @@
 
   /* Entropy encoding: either Huffman or arithmetic coding. */
   if (cinfo->arith_code) {
+#ifdef C_ARITH_CODING_SUPPORTED
+    jinit_arith_encoder(cinfo);
+#else
     ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
   } else {
     if (cinfo->progressive_mode) {
 #ifdef C_PROGRESSIVE_SUPPORTED
diff --git a/jdapistd.c b/jdapistd.c
index c8e3fa0..2343da5 100644
--- a/jdapistd.c
+++ b/jdapistd.c
@@ -2,6 +2,7 @@
  * jdapistd.c
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -17,6 +18,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 /* Forward declarations */
@@ -202,7 +204,7 @@
   }
 
   /* Verify that at least one iMCU row can be returned. */
-  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size;
+  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size;
   if (max_lines < lines_per_iMCU_row)
     ERREXIT(cinfo, JERR_BUFFER_SIZE);
 
diff --git a/jdarith.c b/jdarith.c
new file mode 100644
index 0000000..d556733
--- /dev/null
+++ b/jdarith.c
@@ -0,0 +1,761 @@
+/*
+ * jdarith.c
+ *
+ * Developed 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy decoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy decoder object for arithmetic decoding. */
+
+typedef struct {
+  struct jpeg_entropy_decoder pub; /* public fields */
+
+  INT32 c;       /* C register, base of coding interval + input bit buffer */
+  INT32 a;               /* A register, normalized size of coding interval */
+  int ct;     /* bit shift counter, # of bits left in bit buffer part of C */
+                                                         /* init: ct = -16 */
+                                                         /* run: ct = 0..7 */
+                                                         /* error: ct = -1 */
+  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+  unsigned int restarts_to_go;	/* MCUs left in this restart interval */
+
+  /* Pointers to statistics areas (these workspaces have image lifespan) */
+  unsigned char * dc_stats[NUM_ARITH_TBLS];
+  unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+  /* Statistics bin for coding with fixed probability 0.5 */
+  unsigned char fixed_bin[4];
+} arith_entropy_decoder;
+
+typedef arith_entropy_decoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+
+LOCAL(int)
+get_byte (j_decompress_ptr cinfo)
+/* Read next input byte; we do not support suspension in this module. */
+{
+  struct jpeg_source_mgr * src = cinfo->src;
+
+  if (src->bytes_in_buffer == 0)
+    if (! (*src->fill_input_buffer) (cinfo))
+      ERREXIT(cinfo, JERR_CANT_SUSPEND);
+  src->bytes_in_buffer--;
+  return GETJOCTET(*src->next_input_byte++);
+}
+
+
+/*
+ * The core arithmetic decoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Return value is 0 or 1 (binary decision).
+ *
+ * Note: I've changed the handling of the code base & bit
+ * buffer register C compared to other implementations
+ * based on the standards layout & procedures.
+ * While it also contains both the actual base of the
+ * coding interval (16 bits) and the next-bits buffer,
+ * the cut-point between these two parts is floating
+ * (instead of fixed) with the bit shift counter CT.
+ * Thus, we also need only one (variable instead of
+ * fixed size) shift for the LPS/MPS decision, and
+ * we can get away with any renormalization update
+ * of C (except for new data insertion, of course).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(int)
+arith_decode (j_decompress_ptr cinfo, unsigned char *st)
+{
+  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+  register unsigned char nl, nm;
+  register INT32 qe, temp;
+  register int sv, data;
+
+  /* Renormalization & data input per section D.2.6 */
+  while (e->a < 0x8000L) {
+    if (--e->ct < 0) {
+      /* Need to fetch next data byte */
+      if (cinfo->unread_marker)
+	data = 0;		/* stuff zero data */
+      else {
+	data = get_byte(cinfo);	/* read next input byte */
+	if (data == 0xFF) {	/* zero stuff or marker code */
+	  do data = get_byte(cinfo);
+	  while (data == 0xFF);	/* swallow extra 0xFF bytes */
+	  if (data == 0)
+	    data = 0xFF;	/* discard stuffed zero byte */
+	  else {
+	    /* Note: Different from the Huffman decoder, hitting
+	     * a marker while processing the compressed data
+	     * segment is legal in arithmetic coding.
+	     * The convention is to supply zero data
+	     * then until decoding is complete.
+	     */
+	    cinfo->unread_marker = data;
+	    data = 0;
+	  }
+	}
+      }
+      e->c = (e->c << 8) | data; /* insert data into C register */
+      if ((e->ct += 8) < 0)	 /* update bit shift counter */
+	/* Need more initial bytes */
+	if (++e->ct == 0)
+	  /* Got 2 initial bytes -> re-init A and exit loop */
+	  e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
+    }
+    e->a <<= 1;
+  }
+
+  /* Fetch values from our compact representation of Table D.2:
+   * Qe values and probability estimation state machine
+   */
+  sv = *st;
+  qe = jpeg_aritab[sv & 0x7F];	/* => Qe_Value */
+  nl = qe & 0xFF; qe >>= 8;	/* Next_Index_LPS + Switch_MPS */
+  nm = qe & 0xFF; qe >>= 8;	/* Next_Index_MPS */
+
+  /* Decode & estimation procedures per sections D.2.4 & D.2.5 */
+  temp = e->a - qe;
+  e->a = temp;
+  temp <<= e->ct;
+  if (e->c >= temp) {
+    e->c -= temp;
+    /* Conditional LPS (less probable symbol) exchange */
+    if (e->a < qe) {
+      e->a = qe;
+      *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+    } else {
+      e->a = qe;
+      *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+      sv ^= 0x80;		/* Exchange LPS/MPS */
+    }
+  } else if (e->a < 0x8000L) {
+    /* Conditional MPS (more probable symbol) exchange */
+    if (e->a < qe) {
+      *st = (sv & 0x80) ^ nl;	/* Estimate_after_LPS */
+      sv ^= 0x80;		/* Exchange LPS/MPS */
+    } else {
+      *st = (sv & 0x80) ^ nm;	/* Estimate_after_MPS */
+    }
+  }
+
+  return sv >> 7;
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ */
+
+LOCAL(void)
+process_restart (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci;
+  jpeg_component_info * compptr;
+
+  /* Advance past the RSTn marker */
+  if (! (*cinfo->marker->read_restart_marker) (cinfo))
+    ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+  /* Re-initialize statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+      /* Reset DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    if (! cinfo->progressive_mode || cinfo->Ss) {
+      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+    }
+  }
+
+  /* Reset arithmetic decoding variables */
+  entropy->c = 0;
+  entropy->a = 0;
+  entropy->ct = -16;	/* force reading 2 initial bytes to fill C */
+
+  /* Reset restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Arithmetic MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * arithmetic-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl, sign;
+  int v, m;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.19: Decode_DC_DIFF */
+    if (arith_decode(cinfo, st) == 0)
+      entropy->dc_context[ci] = 0;
+    else {
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, st + 1);
+      st += 2; st += sign;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	st = entropy->dc_stats[tbl] + 20;	/* Table F.4: X1 = 20 */
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;		   /* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+      else
+	entropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      entropy->last_dc_val[ci] += v;
+    }
+
+    /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
+    (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  unsigned char *st;
+  int tbl, sign, k;
+  int v, m;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  /* There is always only one block per MCU */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+  /* Figure F.20: Decode_AC_coefficients */
+  for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    if (arith_decode(cinfo, st)) break;		/* EOB flag */
+    while (arith_decode(cinfo, st + 1) == 0) {
+      st += 3; k++;
+      if (k > cinfo->Se) {
+	WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	entropy->ct = -1;			/* spectral overflow */
+	return TRUE;
+      }
+    }
+    /* Figure F.21: Decoding nonzero value v */
+    /* Figure F.22: Decoding the sign of v */
+    sign = arith_decode(cinfo, entropy->fixed_bin);
+    st += 2;
+    /* Figure F.23: Decoding the magnitude category of v */
+    if ((m = arith_decode(cinfo, st)) != 0) {
+      if (arith_decode(cinfo, st)) {
+	m <<= 1;
+	st = entropy->ac_stats[tbl] +
+	     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+    }
+    v = m;
+    /* Figure F.24: Decoding the magnitude bit pattern of v */
+    st += 14;
+    while (m >>= 1)
+      if (arith_decode(cinfo, st)) v |= m;
+    v += 1; if (sign) v = -v;
+    /* Scale and output coefficient in natural (dezigzagged) order */
+    (*block)[jpeg_natural_order[k]] = (JCOEF) (v << cinfo->Al);
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  unsigned char *st;
+  int p1, blkn;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  st = entropy->fixed_bin;	/* use fixed probability estimation */
+  p1 = 1 << cinfo->Al;		/* 1 in the bit position being coded */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    /* Encoded data is simply the next bit of the two's-complement DC value */
+    if (arith_decode(cinfo, st))
+      MCU_data[blkn][0][0] |= p1;
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  JBLOCKROW block;
+  JCOEFPTR thiscoef;
+  unsigned char *st;
+  int tbl, k, kex;
+  int p1, m1;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  /* There is always only one block per MCU */
+  block = MCU_data[0];
+  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+  p1 = 1 << cinfo->Al;		/* 1 in the bit position being coded */
+  m1 = (-1) << cinfo->Al;	/* -1 in the bit position being coded */
+
+  /* Establish EOBx (previous stage end-of-block) index */
+  for (kex = cinfo->Se; kex > 0; kex--)
+    if ((*block)[jpeg_natural_order[kex]]) break;
+
+  for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+    st = entropy->ac_stats[tbl] + 3 * (k - 1);
+    if (k > kex)
+      if (arith_decode(cinfo, st)) break;	/* EOB flag */
+    for (;;) {
+      thiscoef = *block + jpeg_natural_order[k];
+      if (*thiscoef) {				/* previously nonzero coef */
+	if (arith_decode(cinfo, st + 2)) {
+	  if (*thiscoef < 0)
+	    *thiscoef += m1;
+	  else
+	    *thiscoef += p1;
+	}
+	break;
+      }
+      if (arith_decode(cinfo, st + 1)) {	/* newly nonzero coef */
+	if (arith_decode(cinfo, entropy->fixed_bin))
+	  *thiscoef = m1;
+	else
+	  *thiscoef = p1;
+	break;
+      }
+      st += 3; k++;
+      if (k > cinfo->Se) {
+	WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	entropy->ct = -1;			/* spectral overflow */
+	return TRUE;
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  jpeg_component_info * compptr;
+  JBLOCKROW block;
+  unsigned char *st;
+  int blkn, ci, tbl, sign, k;
+  int v, m;
+
+  /* Process restart marker if needed */
+  if (cinfo->restart_interval) {
+    if (entropy->restarts_to_go == 0)
+      process_restart(cinfo);
+    entropy->restarts_to_go--;
+  }
+
+  if (entropy->ct == -1) return TRUE;	/* if error do nothing */
+
+  /* Outer loop handles each block in the MCU */
+
+  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+    block = MCU_data[blkn];
+    ci = cinfo->MCU_membership[blkn];
+    compptr = cinfo->cur_comp_info[ci];
+
+    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+    tbl = compptr->dc_tbl_no;
+
+    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+    /* Figure F.19: Decode_DC_DIFF */
+    if (arith_decode(cinfo, st) == 0)
+      entropy->dc_context[ci] = 0;
+    else {
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, st + 1);
+      st += 2; st += sign;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	st = entropy->dc_stats[tbl] + 20;	/* Table F.4: X1 = 20 */
+	while (arith_decode(cinfo, st)) {
+	  if ((m <<= 1) == 0x8000) {
+	    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	    entropy->ct = -1;			/* magnitude overflow */
+	    return TRUE;
+	  }
+	  st += 1;
+	}
+      }
+      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+	entropy->dc_context[ci] = 0;		   /* zero diff category */
+      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+	entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+      else
+	entropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      entropy->last_dc_val[ci] += v;
+    }
+
+    (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
+
+    /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+    tbl = compptr->ac_tbl_no;
+
+    /* Figure F.20: Decode_AC_coefficients */
+    for (k = 1; k <= DCTSIZE2 - 1; k++) {
+      st = entropy->ac_stats[tbl] + 3 * (k - 1);
+      if (arith_decode(cinfo, st)) break;	/* EOB flag */
+      while (arith_decode(cinfo, st + 1) == 0) {
+	st += 3; k++;
+	if (k > DCTSIZE2 - 1) {
+	  WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	  entropy->ct = -1;			/* spectral overflow */
+	  return TRUE;
+	}
+      }
+      /* Figure F.21: Decoding nonzero value v */
+      /* Figure F.22: Decoding the sign of v */
+      sign = arith_decode(cinfo, entropy->fixed_bin);
+      st += 2;
+      /* Figure F.23: Decoding the magnitude category of v */
+      if ((m = arith_decode(cinfo, st)) != 0) {
+	if (arith_decode(cinfo, st)) {
+	  m <<= 1;
+	  st = entropy->ac_stats[tbl] +
+	       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+	  while (arith_decode(cinfo, st)) {
+	    if ((m <<= 1) == 0x8000) {
+	      WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+	      entropy->ct = -1;			/* magnitude overflow */
+	      return TRUE;
+	    }
+	    st += 1;
+	  }
+	}
+      }
+      v = m;
+      /* Figure F.24: Decoding the magnitude bit pattern of v */
+      st += 14;
+      while (m >>= 1)
+	if (arith_decode(cinfo, st)) v |= m;
+      v += 1; if (sign) v = -v;
+      (*block)[jpeg_natural_order[k]] = (JCOEF) v;
+    }
+  }
+
+  return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+  int ci, tbl;
+  jpeg_component_info * compptr;
+
+  if (cinfo->progressive_mode) {
+    /* Validate progressive scan parameters */
+    if (cinfo->Ss == 0) {
+      if (cinfo->Se != 0)
+	goto bad;
+    } else {
+      /* need not check Ss/Se < 0 since they came from unsigned bytes */
+      if (cinfo->Se < cinfo->Ss || cinfo->Se > DCTSIZE2 - 1)
+	goto bad;
+      /* AC scans may have only one component */
+      if (cinfo->comps_in_scan != 1)
+	goto bad;
+    }
+    if (cinfo->Ah != 0) {
+      /* Successive approximation refinement scan: must have Al = Ah-1. */
+      if (cinfo->Ah-1 != cinfo->Al)
+	goto bad;
+    }
+    if (cinfo->Al > 13) {	/* need not check for < 0 */
+      bad:
+      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+	       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+    }
+    /* Update progression status, and verify that scan order is legal.
+     * Note that inter-scan inconsistencies are treated as warnings
+     * not fatal errors ... not clear if this is right way to behave.
+     */
+    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+      int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+      int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+      if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+	WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+      for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+	int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+	if (cinfo->Ah != expected)
+	  WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+	coef_bit_ptr[coefi] = cinfo->Al;
+      }
+    }
+    /* Select MCU decoding routine */
+    if (cinfo->Ah == 0) {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_first;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_first;
+    } else {
+      if (cinfo->Ss == 0)
+	entropy->pub.decode_mcu = decode_mcu_DC_refine;
+      else
+	entropy->pub.decode_mcu = decode_mcu_AC_refine;
+    }
+  } else {
+    /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+     * This ought to be an error condition, but we make it a warning.
+     */
+    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+	(cinfo->Se < DCTSIZE2 && cinfo->Se != DCTSIZE2 - 1))
+      WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+    /* Select MCU decoding routine */
+    entropy->pub.decode_mcu = decode_mcu;
+  }
+
+  /* Allocate & initialize requested statistics areas */
+  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+      tbl = compptr->dc_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->dc_stats[tbl] == NULL)
+	entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+      /* Initialize DC predictions to 0 */
+      entropy->last_dc_val[ci] = 0;
+      entropy->dc_context[ci] = 0;
+    }
+    if (! cinfo->progressive_mode || cinfo->Ss) {
+      tbl = compptr->ac_tbl_no;
+      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+	ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+      if (entropy->ac_stats[tbl] == NULL)
+	entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+	  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+    }
+  }
+
+  /* Initialize arithmetic decoding variables */
+  entropy->c = 0;
+  entropy->a = 0;
+  entropy->ct = -16;	/* force reading 2 initial bytes to fill C */
+
+  /* Initialize restart counter */
+  entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_arith_decoder (j_decompress_ptr cinfo)
+{
+  arith_entropy_ptr entropy;
+  int i;
+
+  entropy = (arith_entropy_ptr)
+    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				SIZEOF(arith_entropy_decoder));
+  cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+  entropy->pub.start_pass = start_pass;
+
+  /* Mark tables unallocated */
+  for (i = 0; i < NUM_ARITH_TBLS; i++) {
+    entropy->dc_stats[i] = NULL;
+    entropy->ac_stats[i] = NULL;
+  }
+
+  /* Initialize index for fixed probability estimation */
+  entropy->fixed_bin[0] = 113;
+
+  if (cinfo->progressive_mode) {
+    /* Create progression status table */
+    int *coef_bit_ptr, ci;
+    cinfo->coef_bits = (int (*)[DCTSIZE2])
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+				  cinfo->num_components*DCTSIZE2*SIZEOF(int));
+    coef_bit_ptr = & cinfo->coef_bits[0][0];
+    for (ci = 0; ci < cinfo->num_components; ci++) 
+      for (i = 0; i < DCTSIZE2; i++)
+	*coef_bit_ptr++ = -1;
+  }
+}
diff --git a/jdatadst.c b/jdatadst.c
index a8f6fb0..2f48869 100644
--- a/jdatadst.c
+++ b/jdatadst.c
@@ -2,13 +2,14 @@
  * jdatadst.c
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains compression data destination routines for the case of
- * emitting JPEG data to a file (or any stdio stream).  While these routines
- * are sufficient for most applications, some will want to use a different
- * destination manager.
+ * emitting JPEG data to memory or to a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different destination manager.
  * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
  * JOCTETs into 8-bit-wide elements on external storage.  If char is wider
  * than 8 bits on your machine, you may need to do some tweaking.
@@ -19,6 +20,11 @@
 #include "jpeglib.h"
 #include "jerror.h"
 
+#ifndef HAVE_STDLIB_H		/* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
 
 /* Expanded data destination object for stdio output */
 
@@ -34,6 +40,23 @@
 #define OUTPUT_BUF_SIZE  4096	/* choose an efficiently fwrite'able size */
 
 
+#if JPEG_LIB_VERSION >= 80
+/* Expanded data destination object for memory output */
+
+typedef struct {
+  struct jpeg_destination_mgr pub; /* public fields */
+
+  unsigned char ** outbuffer;	/* target buffer */
+  unsigned long * outsize;
+  unsigned char * newbuffer;	/* newly allocated buffer */
+  JOCTET * buffer;		/* start of buffer */
+  size_t bufsize;
+} my_mem_destination_mgr;
+
+typedef my_mem_destination_mgr * my_mem_dest_ptr;
+#endif
+
+
 /*
  * Initialize destination --- called by jpeg_start_compress
  * before any data is actually written.
@@ -53,6 +76,14 @@
   dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
 }
 
+#if JPEG_LIB_VERSION >= 80
+METHODDEF(void)
+init_mem_destination (j_compress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+#endif
+
 
 /*
  * Empty the output buffer --- called whenever buffer fills up.
@@ -92,6 +123,38 @@
   return TRUE;
 }
 
+#if JPEG_LIB_VERSION >= 80
+METHODDEF(boolean)
+empty_mem_output_buffer (j_compress_ptr cinfo)
+{
+  size_t nextsize;
+  JOCTET * nextbuffer;
+  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+  /* Try to allocate new buffer with double size */
+  nextsize = dest->bufsize * 2;
+  nextbuffer = malloc(nextsize);
+
+  if (nextbuffer == NULL)
+    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+
+  MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+
+  if (dest->newbuffer != NULL)
+    free(dest->newbuffer);
+
+  dest->newbuffer = nextbuffer;
+
+  dest->pub.next_output_byte = nextbuffer + dest->bufsize;
+  dest->pub.free_in_buffer = dest->bufsize;
+
+  dest->buffer = nextbuffer;
+  dest->bufsize = nextsize;
+
+  return TRUE;
+}
+#endif
+
 
 /*
  * Terminate destination --- called by jpeg_finish_compress
@@ -119,6 +182,17 @@
     ERREXIT(cinfo, JERR_FILE_WRITE);
 }
 
+#if JPEG_LIB_VERSION >= 80
+METHODDEF(void)
+term_mem_destination (j_compress_ptr cinfo)
+{
+  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+  *dest->outbuffer = dest->buffer;
+  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
+}
+#endif
+
 
 /*
  * Prepare for output to a stdio stream.
@@ -149,3 +223,55 @@
   dest->pub.term_destination = term_destination;
   dest->outfile = outfile;
 }
+
+
+#if JPEG_LIB_VERSION >= 80
+/*
+ * Prepare for output to a memory buffer.
+ * The caller may supply an own initial buffer with appropriate size.
+ * Otherwise, or when the actual data output exceeds the given size,
+ * the library adapts the buffer size as necessary.
+ * The standard library functions malloc/free are used for allocating
+ * larger memory, so the buffer is available to the application after
+ * finishing compression, and then the application is responsible for
+ * freeing the requested memory.
+ */
+
+GLOBAL(void)
+jpeg_mem_dest (j_compress_ptr cinfo,
+	       unsigned char ** outbuffer, unsigned long * outsize)
+{
+  my_mem_dest_ptr dest;
+
+  if (outbuffer == NULL || outsize == NULL)	/* sanity check */
+    ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+  /* The destination object is made permanent so that multiple JPEG images
+   * can be written to the same buffer without re-executing jpeg_mem_dest.
+   */
+  if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
+    cinfo->dest = (struct jpeg_destination_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(my_mem_destination_mgr));
+  }
+
+  dest = (my_mem_dest_ptr) cinfo->dest;
+  dest->pub.init_destination = init_mem_destination;
+  dest->pub.empty_output_buffer = empty_mem_output_buffer;
+  dest->pub.term_destination = term_mem_destination;
+  dest->outbuffer = outbuffer;
+  dest->outsize = outsize;
+  dest->newbuffer = NULL;
+
+  if (*outbuffer == NULL || *outsize == 0) {
+    /* Allocate initial buffer */
+    dest->newbuffer = *outbuffer = malloc(OUTPUT_BUF_SIZE);
+    if (dest->newbuffer == NULL)
+      ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+    *outsize = OUTPUT_BUF_SIZE;
+  }
+
+  dest->pub.next_output_byte = dest->buffer = *outbuffer;
+  dest->pub.free_in_buffer = dest->bufsize = *outsize;
+}
+#endif
diff --git a/jdatasrc.c b/jdatasrc.c
index edc752b..7609f76 100644
--- a/jdatasrc.c
+++ b/jdatasrc.c
@@ -2,13 +2,14 @@
  * jdatasrc.c
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2010 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains decompression data source routines for the case of
- * reading JPEG data from a file (or any stdio stream).  While these routines
- * are sufficient for most applications, some will want to use a different
- * source manager.
+ * reading JPEG data from memory or from a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different source manager.
  * IMPORTANT: we assume that fread() will correctly transcribe an array of
  * JOCTETs from 8-bit-wide elements on external storage.  If char is wider
  * than 8 bits on your machine, you may need to do some tweaking.
@@ -52,6 +53,14 @@
   src->start_of_file = TRUE;
 }
 
+#if JPEG_LIB_VERSION >= 80
+METHODDEF(void)
+init_mem_source (j_decompress_ptr cinfo)
+{
+  /* no work necessary here */
+}
+#endif
+
 
 /*
  * Fill the input buffer --- called whenever buffer is emptied.
@@ -111,6 +120,28 @@
   return TRUE;
 }
 
+#if JPEG_LIB_VERSION >= 80
+METHODDEF(boolean)
+fill_mem_input_buffer (j_decompress_ptr cinfo)
+{
+  static JOCTET mybuffer[4];
+
+  /* The whole JPEG data is expected to reside in the supplied memory
+   * buffer, so any request for more data beyond the given buffer size
+   * is treated as an error.
+   */
+  WARNMS(cinfo, JWRN_JPEG_EOF);
+  /* Insert a fake EOI marker */
+  mybuffer[0] = (JOCTET) 0xFF;
+  mybuffer[1] = (JOCTET) JPEG_EOI;
+
+  cinfo->src->next_input_byte = mybuffer;
+  cinfo->src->bytes_in_buffer = 2;
+
+  return TRUE;
+}
+#endif
+
 
 /*
  * Skip data --- used to skip over a potentially large amount of
@@ -127,22 +158,22 @@
 METHODDEF(void)
 skip_input_data (j_decompress_ptr cinfo, long num_bytes)
 {
-  my_src_ptr src = (my_src_ptr) cinfo->src;
+  struct jpeg_source_mgr * src = cinfo->src;
 
   /* Just a dumb implementation for now.  Could use fseek() except
    * it doesn't work on pipes.  Not clear that being smart is worth
    * any trouble anyway --- large skips are infrequent.
    */
   if (num_bytes > 0) {
-    while (num_bytes > (long) src->pub.bytes_in_buffer) {
-      num_bytes -= (long) src->pub.bytes_in_buffer;
-      (void) fill_input_buffer(cinfo);
+    while (num_bytes > (long) src->bytes_in_buffer) {
+      num_bytes -= (long) src->bytes_in_buffer;
+      (void) (*src->fill_input_buffer) (cinfo);
       /* note we assume that fill_input_buffer will never return FALSE,
        * so suspension need not be handled.
        */
     }
-    src->pub.next_input_byte += (size_t) num_bytes;
-    src->pub.bytes_in_buffer -= (size_t) num_bytes;
+    src->next_input_byte += (size_t) num_bytes;
+    src->bytes_in_buffer -= (size_t) num_bytes;
   }
 }
 
@@ -210,3 +241,40 @@
   src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
   src->pub.next_input_byte = NULL; /* until buffer loaded */
 }
+
+
+#if JPEG_LIB_VERSION >= 80
+/*
+ * Prepare for input from a supplied memory buffer.
+ * The buffer must contain the whole JPEG data.
+ */
+
+GLOBAL(void)
+jpeg_mem_src (j_decompress_ptr cinfo,
+	      unsigned char * inbuffer, unsigned long insize)
+{
+  struct jpeg_source_mgr * src;
+
+  if (inbuffer == NULL || insize == 0)	/* Treat empty input as fatal error */
+    ERREXIT(cinfo, JERR_INPUT_EMPTY);
+
+  /* The source object is made permanent so that a series of JPEG images
+   * can be read from the same buffer by calling jpeg_mem_src only before
+   * the first one.
+   */
+  if (cinfo->src == NULL) {	/* first time for this JPEG object? */
+    cinfo->src = (struct jpeg_source_mgr *)
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+				  SIZEOF(struct jpeg_source_mgr));
+  }
+
+  src = cinfo->src;
+  src->init_source = init_mem_source;
+  src->fill_input_buffer = fill_mem_input_buffer;
+  src->skip_input_data = skip_input_data;
+  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+  src->term_source = term_source;
+  src->bytes_in_buffer = (size_t) insize;
+  src->next_input_byte = (JOCTET *) inbuffer;
+}
+#endif
diff --git a/jdcoefct.c b/jdcoefct.c
index f56af5f..48a9fc6 100644
--- a/jdcoefct.c
+++ b/jdcoefct.c
@@ -2,6 +2,7 @@
  * jdcoefct.c
  *
  * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -17,6 +18,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 /* Block smoothing is only applicable for progressive JPEG, so: */
 #ifndef D_PROGRESSIVE_SUPPORTED
@@ -190,7 +192,7 @@
 	useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
 						    : compptr->last_col_width;
 	output_ptr = output_buf[compptr->component_index] +
-	  yoffset * compptr->DCT_scaled_size;
+	  yoffset * compptr->_DCT_scaled_size;
 	start_col = MCU_col_num * compptr->MCU_sample_width;
 	for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
 	  if (cinfo->input_iMCU_row < last_iMCU_row ||
@@ -200,11 +202,11 @@
 	      (*inverse_DCT) (cinfo, compptr,
 			      (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
 			      output_ptr, output_col);
-	      output_col += compptr->DCT_scaled_size;
+	      output_col += compptr->_DCT_scaled_size;
 	    }
 	  }
 	  blkn += compptr->MCU_width;
-	  output_ptr += compptr->DCT_scaled_size;
+	  output_ptr += compptr->_DCT_scaled_size;
 	}
       }
     }
@@ -365,9 +367,9 @@
 	(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
 			output_ptr, output_col);
 	buffer_ptr++;
-	output_col += compptr->DCT_scaled_size;
+	output_col += compptr->_DCT_scaled_size;
       }
-      output_ptr += compptr->DCT_scaled_size;
+      output_ptr += compptr->_DCT_scaled_size;
     }
   }
 
@@ -660,9 +662,9 @@
 	DC4 = DC5; DC5 = DC6;
 	DC7 = DC8; DC8 = DC9;
 	buffer_ptr++, prev_block_row++, next_block_row++;
-	output_col += compptr->DCT_scaled_size;
+	output_col += compptr->_DCT_scaled_size;
       }
-      output_ptr += compptr->DCT_scaled_size;
+      output_ptr += compptr->_DCT_scaled_size;
     }
   }
 
diff --git a/jdcolor.c b/jdcolor.c
index e02ea4f..bc73b3f 100644
--- a/jdcolor.c
+++ b/jdcolor.c
@@ -223,7 +223,6 @@
 {
   register JSAMPROW inptr, outptr;
   JSAMPLE *maxinptr;
-  register JDIMENSION col;
   JDIMENSION num_cols = cinfo->output_width;
   int rindex = rgb_red[cinfo->out_color_space];
   int gindex = rgb_green[cinfo->out_color_space];
diff --git a/jddctmgr.c b/jddctmgr.c
index 52f5090..044e469 100644
--- a/jddctmgr.c
+++ b/jddctmgr.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -21,6 +22,7 @@
 #include "jpeglib.h"
 #include "jdct.h"		/* Private declarations for DCT subsystem */
 #include "jsimddct.h"
+#include "jpegcomp.h"
 
 
 /*
@@ -100,7 +102,7 @@
   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
        ci++, compptr++) {
     /* Select the proper IDCT routine for this component's scaling */
-    switch (compptr->DCT_scaled_size) {
+    switch (compptr->_DCT_scaled_size) {
 #ifdef IDCT_SCALING_SUPPORTED
     case 1:
       method_ptr = jpeg_idct_1x1;
@@ -156,7 +158,7 @@
       }
       break;
     default:
-      ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size);
+      ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->_DCT_scaled_size);
       break;
     }
     idct->pub.inverse_DCT[ci] = method_ptr;
diff --git a/jdhuff.c b/jdhuff.c
index a40c2ff..12db124 100644
--- a/jdhuff.c
+++ b/jdhuff.c
@@ -2,6 +2,7 @@
  * jdhuff.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -14,7 +15,7 @@
  * storage only upon successful completion of an MCU.
  */
 
-/* Modifications:
+/* Performance enhancements:
  * Copyright (C)2007 Sun Microsystems, Inc.
  * Copyright (C)2009-2010 D. R. Commander
  *
@@ -33,6 +34,7 @@
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jdhuff.h"		/* Declarations shared with jdphuff.c */
+#include "jpegcomp.h"
 
 
 /*
@@ -137,7 +139,7 @@
     if (compptr->component_needed) {
       entropy->dc_needed[blkn] = TRUE;
       /* we don't need the ACs if producing a 1/8th-size image */
-      entropy->ac_needed[blkn] = (compptr->DCT_scaled_size > 1);
+      entropy->ac_needed[blkn] = (compptr->_DCT_scaled_size > 1);
     } else {
       entropy->dc_needed[blkn] = entropy->ac_needed[blkn] = FALSE;
     }
@@ -782,7 +784,7 @@
     usefast = 0;
   }
 
-  if (cinfo->src->bytes_in_buffer < BUFSIZE * cinfo->blocks_in_MCU
+  if (cinfo->src->bytes_in_buffer < BUFSIZE * (size_t)cinfo->blocks_in_MCU
     || cinfo->unread_marker != 0)
     usefast = 0;
 
diff --git a/jdinput.c b/jdinput.c
index 0c2ac8f..9fcd089 100644
--- a/jdinput.c
+++ b/jdinput.c
@@ -2,6 +2,8 @@
  * jdinput.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -14,6 +16,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 /* Private state */
@@ -35,6 +38,79 @@
  * Routines to calculate various quantities related to the size of the image.
  */
 
+
+#if JPEG_LIB_VERSION >= 80
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_core_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for transcoding and full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+  int ci;
+  jpeg_component_info *compptr;
+
+  /* Compute actual output image dimensions and DCT scaling choices. */
+  if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) {
+    /* Provide 1/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 1;
+    cinfo->min_DCT_v_scaled_size = 1;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) {
+    /* Provide 2/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 2;
+    cinfo->min_DCT_v_scaled_size = 2;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) {
+    /* Provide 4/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 4;
+    cinfo->min_DCT_v_scaled_size = 4;
+  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) {
+    /* Provide 8/block_size scaling */
+    cinfo->output_width = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size);
+    cinfo->output_height = (JDIMENSION)
+      jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size);
+    cinfo->min_DCT_h_scaled_size = 8;
+    cinfo->min_DCT_v_scaled_size = 8;
+  }
+  /* Recompute dimensions of components */
+  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+       ci++, compptr++) {
+    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size;
+    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size;
+  }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+  /* Hardwire it to "no scaling" */
+  cinfo->output_width = cinfo->image_width;
+  cinfo->output_height = cinfo->image_height;
+  /* jdinput.c has already initialized DCT_scaled_size,
+   * and has computed unscaled downsampled_width and downsampled_height.
+   */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+}
+#endif
+
+
 LOCAL(void)
 initial_setup (j_decompress_ptr cinfo)
 /* Called once, when first SOS marker is reached */
@@ -70,16 +146,30 @@
 				   compptr->v_samp_factor);
   }
 
+#if JPEG_LIB_VERSION >=80
+    cinfo->block_size = DCTSIZE;
+    cinfo->natural_order = jpeg_natural_order;
+    cinfo->lim_Se = DCTSIZE2-1;
+#endif
+
   /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
    * In the full decompressor, this will be overridden by jdmaster.c;
    * but in the transcoder, jdmaster.c is not used, so we must do it here.
    */
+#if JPEG_LIB_VERSION >= 70
+  cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = DCTSIZE;
+#else
   cinfo->min_DCT_scaled_size = DCTSIZE;
+#endif
 
   /* Compute dimensions of components */
   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
        ci++, compptr++) {
+#if JPEG_LIB_VERSION >= 70
+    compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+#else
     compptr->DCT_scaled_size = DCTSIZE;
+#endif
     /* Size in DCT blocks */
     compptr->width_in_blocks = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
@@ -138,7 +228,7 @@
     compptr->MCU_width = 1;
     compptr->MCU_height = 1;
     compptr->MCU_blocks = 1;
-    compptr->MCU_sample_width = compptr->DCT_scaled_size;
+    compptr->MCU_sample_width = compptr->_DCT_scaled_size;
     compptr->last_col_width = 1;
     /* For noninterleaved scans, it is convenient to define last_row_height
      * as the number of block rows present in the last iMCU row.
@@ -174,7 +264,7 @@
       compptr->MCU_width = compptr->h_samp_factor;
       compptr->MCU_height = compptr->v_samp_factor;
       compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
-      compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size;
+      compptr->MCU_sample_width = compptr->MCU_width * compptr->_DCT_scaled_size;
       /* Figure number of non-dummy blocks in last MCU column & row */
       tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
       if (tmp == 0) tmp = compptr->MCU_width;
diff --git a/jdmainct.c b/jdmainct.c
index 13c956f..eb32cae 100644
--- a/jdmainct.c
+++ b/jdmainct.c
@@ -2,6 +2,7 @@
  * jdmainct.c
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -16,6 +17,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 /*
@@ -159,24 +161,24 @@
  * This is done only once, not once per pass.
  */
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
   int ci, rgroup;
-  int M = cinfo->min_DCT_scaled_size;
+  int M = cinfo->_min_DCT_scaled_size;
   jpeg_component_info *compptr;
   JSAMPARRAY xbuf;
 
   /* Get top-level space for component array pointers.
    * We alloc both arrays with one call to save a few cycles.
    */
-  main->xbuffer[0] = (JSAMPIMAGE)
+  main_ptr->xbuffer[0] = (JSAMPIMAGE)
     (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
 				cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
-  main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
+  main_ptr->xbuffer[1] = main_ptr->xbuffer[0] + cinfo->num_components;
 
   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 */
+    rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
+      cinfo->_min_DCT_scaled_size; /* height of a row group of component */
     /* Get space for pointer lists --- M+4 row groups in each list.
      * We alloc both pointer lists with one call to save a few cycles.
      */
@@ -184,9 +186,9 @@
       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
 				  2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
     xbuf += rgroup;		/* want one row group at negative offsets */
-    main->xbuffer[0][ci] = xbuf;
+    main_ptr->xbuffer[0][ci] = xbuf;
     xbuf += rgroup * (M + 4);
-    main->xbuffer[1][ci] = xbuf;
+    main_ptr->xbuffer[1][ci] = xbuf;
   }
 }
 
@@ -194,26 +196,26 @@
 LOCAL(void)
 make_funny_pointers (j_decompress_ptr cinfo)
 /* Create the funny pointer lists discussed in the comments above.
- * The actual workspace is already allocated (in main->buffer),
+ * The actual workspace is already allocated (in main_ptr->buffer),
  * and the space for the pointer lists is allocated too.
  * This routine just fills in the curiously ordered lists.
  * This will be repeated at the beginning of each pass.
  */
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
   int ci, i, rgroup;
-  int M = cinfo->min_DCT_scaled_size;
+  int M = cinfo->_min_DCT_scaled_size;
   jpeg_component_info *compptr;
   JSAMPARRAY buf, 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->xbuffer[0][ci];
-    xbuf1 = main->xbuffer[1][ci];
+    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];
     /* First copy the workspace pointers as-is */
-    buf = main->buffer[ci];
+    buf = main_ptr->buffer[ci];
     for (i = 0; i < rgroup * (M + 2); i++) {
       xbuf0[i] = xbuf1[i] = buf[i];
     }
@@ -240,18 +242,18 @@
  * This changes the pointer list state from top-of-image to the normal state.
  */
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
   int ci, i, rgroup;
-  int M = cinfo->min_DCT_scaled_size;
+  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->xbuffer[0][ci];
-    xbuf1 = main->xbuffer[1][ci];
+    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];
@@ -269,7 +271,7 @@
  * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
  */
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
   int ci, i, rgroup, iMCUheight, rows_left;
   jpeg_component_info *compptr;
   JSAMPARRAY xbuf;
@@ -277,8 +279,8 @@
   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
        ci++, compptr++) {
     /* Count sample rows in one iMCU row and in one row group */
-    iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size;
-    rgroup = iMCUheight / cinfo->min_DCT_scaled_size;
+    iMCUheight = compptr->v_samp_factor * compptr->_DCT_scaled_size;
+    rgroup = iMCUheight / cinfo->_min_DCT_scaled_size;
     /* Count nondummy sample rows remaining for this component */
     rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
     if (rows_left == 0) rows_left = iMCUheight;
@@ -286,12 +288,12 @@
      * so we need only do it once.
      */
     if (ci == 0) {
-      main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+      main_ptr->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
     }
     /* Duplicate the last real sample row rgroup*2 times; this pads out the
      * last partial rowgroup and ensures at least one full rowgroup of context.
      */
-    xbuf = main->xbuffer[main->whichptr][ci];
+    xbuf = main_ptr->xbuffer[main_ptr->whichptr][ci];
     for (i = 0; i < rgroup * 2; i++) {
       xbuf[rows_left + i] = xbuf[rows_left-1];
     }
@@ -306,27 +308,27 @@
 METHODDEF(void)
 start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
 
   switch (pass_mode) {
   case JBUF_PASS_THRU:
     if (cinfo->upsample->need_context_rows) {
-      main->pub.process_data = process_data_context_main;
+      main_ptr->pub.process_data = process_data_context_main;
       make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
-      main->whichptr = 0;	/* Read first iMCU row into xbuffer[0] */
-      main->context_state = CTX_PREPARE_FOR_IMCU;
-      main->iMCU_row_ctr = 0;
+      main_ptr->whichptr = 0;	/* Read first iMCU row into xbuffer[0] */
+      main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
+      main_ptr->iMCU_row_ctr = 0;
     } else {
       /* Simple case with no context needed */
-      main->pub.process_data = process_data_simple_main;
+      main_ptr->pub.process_data = process_data_simple_main;
     }
-    main->buffer_full = FALSE;	/* Mark buffer empty */
-    main->rowgroup_ctr = 0;
+    main_ptr->buffer_full = FALSE;	/* Mark buffer empty */
+    main_ptr->rowgroup_ctr = 0;
     break;
 #ifdef QUANT_2PASS_SUPPORTED
   case JBUF_CRANK_DEST:
     /* For last pass of 2-pass quantization, just crank the postprocessor */
-    main->pub.process_data = process_data_crank_post;
+    main_ptr->pub.process_data = process_data_crank_post;
     break;
 #endif
   default:
@@ -346,32 +348,32 @@
 			  JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
 			  JDIMENSION out_rows_avail)
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
   JDIMENSION rowgroups_avail;
 
   /* Read input data if we haven't filled the main buffer yet */
-  if (! main->buffer_full) {
-    if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
+  if (! main_ptr->buffer_full) {
+    if (! (*cinfo->coef->decompress_data) (cinfo, main_ptr->buffer))
       return;			/* suspension forced, can do nothing more */
-    main->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
+    main_ptr->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
   }
 
   /* There are always min_DCT_scaled_size row groups in an iMCU row. */
-  rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size;
+  rowgroups_avail = (JDIMENSION) cinfo->_min_DCT_scaled_size;
   /* Note: at the bottom of the image, we may pass extra garbage row groups
    * to the postprocessor.  The postprocessor has to check for bottom
    * of image anyway (at row resolution), so no point in us doing it too.
    */
 
   /* Feed the postprocessor */
-  (*cinfo->post->post_process_data) (cinfo, main->buffer,
-				     &main->rowgroup_ctr, rowgroups_avail,
+  (*cinfo->post->post_process_data) (cinfo, main_ptr->buffer,
+				     &main_ptr->rowgroup_ctr, rowgroups_avail,
 				     output_buf, out_row_ctr, out_rows_avail);
 
   /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
-  if (main->rowgroup_ctr >= rowgroups_avail) {
-    main->buffer_full = FALSE;
-    main->rowgroup_ctr = 0;
+  if (main_ptr->rowgroup_ctr >= rowgroups_avail) {
+    main_ptr->buffer_full = FALSE;
+    main_ptr->rowgroup_ctr = 0;
   }
 }
 
@@ -386,15 +388,15 @@
 			   JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
 			   JDIMENSION out_rows_avail)
 {
-  my_main_ptr main = (my_main_ptr) cinfo->main;
+  my_main_ptr main_ptr = (my_main_ptr) cinfo->main;
 
   /* Read input data if we haven't filled the main buffer yet */
-  if (! main->buffer_full) {
+  if (! main_ptr->buffer_full) {
     if (! (*cinfo->coef->decompress_data) (cinfo,
-					   main->xbuffer[main->whichptr]))
+					   main_ptr->xbuffer[main_ptr->whichptr]))
       return;			/* suspension forced, can do nothing more */
-    main->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
-    main->iMCU_row_ctr++;	/* count rows received */
+    main_ptr->buffer_full = TRUE;	/* OK, we have an iMCU row to work with */
+    main_ptr->iMCU_row_ctr++;	/* count rows received */
   }
 
   /* Postprocessor typically will not swallow all the input data it is handed
@@ -402,47 +404,47 @@
    * to exit and restart.  This switch lets us keep track of how far we got.
    * Note that each case falls through to the next on successful completion.
    */
-  switch (main->context_state) {
+  switch (main_ptr->context_state) {
   case CTX_POSTPONED_ROW:
     /* Call postprocessor using previously set pointers for postponed row */
-    (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
-			&main->rowgroup_ctr, main->rowgroups_avail,
+    (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
+			&main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
 			output_buf, out_row_ctr, out_rows_avail);
-    if (main->rowgroup_ctr < main->rowgroups_avail)
+    if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
       return;			/* Need to suspend */
-    main->context_state = CTX_PREPARE_FOR_IMCU;
+    main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
     if (*out_row_ctr >= out_rows_avail)
       return;			/* Postprocessor exactly filled output buf */
     /*FALLTHROUGH*/
   case CTX_PREPARE_FOR_IMCU:
     /* Prepare to process first M-1 row groups of this iMCU row */
-    main->rowgroup_ctr = 0;
-    main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1);
+    main_ptr->rowgroup_ctr = 0;
+    main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->_min_DCT_scaled_size - 1);
     /* Check for bottom of image: if so, tweak pointers to "duplicate"
      * the last sample row, and adjust rowgroups_avail to ignore padding rows.
      */
-    if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
+    if (main_ptr->iMCU_row_ctr == cinfo->total_iMCU_rows)
       set_bottom_pointers(cinfo);
-    main->context_state = CTX_PROCESS_IMCU;
+    main_ptr->context_state = CTX_PROCESS_IMCU;
     /*FALLTHROUGH*/
   case CTX_PROCESS_IMCU:
     /* Call postprocessor using previously set pointers */
-    (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
-			&main->rowgroup_ctr, main->rowgroups_avail,
+    (*cinfo->post->post_process_data) (cinfo, main_ptr->xbuffer[main_ptr->whichptr],
+			&main_ptr->rowgroup_ctr, main_ptr->rowgroups_avail,
 			output_buf, out_row_ctr, out_rows_avail);
-    if (main->rowgroup_ctr < main->rowgroups_avail)
+    if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
       return;			/* Need to suspend */
     /* After the first iMCU, change wraparound pointers to normal state */
-    if (main->iMCU_row_ctr == 1)
+    if (main_ptr->iMCU_row_ctr == 1)
       set_wraparound_pointers(cinfo);
     /* Prepare to load new iMCU row using other xbuffer list */
-    main->whichptr ^= 1;	/* 0=>1 or 1=>0 */
-    main->buffer_full = FALSE;
+    main_ptr->whichptr ^= 1;	/* 0=>1 or 1=>0 */
+    main_ptr->buffer_full = FALSE;
     /* Still need to process last row group of this iMCU row, */
     /* which is saved at index M+1 of the other xbuffer */
-    main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1);
-    main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2);
-    main->context_state = CTX_POSTPONED_ROW;
+    main_ptr->rowgroup_ctr = (JDIMENSION) (cinfo->_min_DCT_scaled_size + 1);
+    main_ptr->rowgroups_avail = (JDIMENSION) (cinfo->_min_DCT_scaled_size + 2);
+    main_ptr->context_state = CTX_POSTPONED_ROW;
   }
 }
 
@@ -475,15 +477,15 @@
 GLOBAL(void)
 jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
 {
-  my_main_ptr main;
+  my_main_ptr main_ptr;
   int ci, rgroup, ngroups;
   jpeg_component_info *compptr;
 
-  main = (my_main_ptr)
+  main_ptr = (my_main_ptr)
     (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
 				SIZEOF(my_main_controller));
-  cinfo->main = (struct jpeg_d_main_controller *) main;
-  main->pub.start_pass = start_pass_main;
+  cinfo->main = (struct jpeg_d_main_controller *) main_ptr;
+  main_ptr->pub.start_pass = start_pass_main;
 
   if (need_full_buffer)		/* shouldn't happen */
     ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -492,21 +494,21 @@
    * ngroups is the number of row groups we need.
    */
   if (cinfo->upsample->need_context_rows) {
-    if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */
+    if (cinfo->_min_DCT_scaled_size < 2) /* unsupported, see comments above */
       ERREXIT(cinfo, JERR_NOTIMPL);
     alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
-    ngroups = cinfo->min_DCT_scaled_size + 2;
+    ngroups = cinfo->_min_DCT_scaled_size + 2;
   } else {
-    ngroups = cinfo->min_DCT_scaled_size;
+    ngroups = cinfo->_min_DCT_scaled_size;
   }
 
   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 */
-    main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+    rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
+      cinfo->_min_DCT_scaled_size; /* height of a row group of component */
+    main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
 			((j_common_ptr) cinfo, JPOOL_IMAGE,
-			 compptr->width_in_blocks * compptr->DCT_scaled_size,
+			 compptr->width_in_blocks * compptr->_DCT_scaled_size,
 			 (JDIMENSION) (rgroup * ngroups));
   }
 }
diff --git a/jdmaster.c b/jdmaster.c
index 8314b67..14520da 100644
--- a/jdmaster.c
+++ b/jdmaster.c
@@ -2,7 +2,7 @@
  * jdmaster.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
- * Copyright (C) 2009, D. R. Commander.
+ * Copyright (C) 2009-2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -15,6 +15,7 @@
 #define JPEG_INTERNALS
 #include "jinclude.h"
 #include "jpeglib.h"
+#include "jpegcomp.h"
 
 
 /* Private state */
@@ -68,9 +69,9 @@
       cinfo->comp_info[2].v_samp_factor != 1)
     return FALSE;
   /* furthermore, it doesn't work if we've scaled the IDCTs differently */
-  if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
-      cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size ||
-      cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size)
+  if (cinfo->comp_info[0]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
+      cinfo->comp_info[1]._DCT_scaled_size != cinfo->_min_DCT_scaled_size ||
+      cinfo->comp_info[2]._DCT_scaled_size != cinfo->_min_DCT_scaled_size)
     return FALSE;
   /* ??? also need to test for upsample-time rescaling, when & if supported */
   return TRUE;			/* by golly, it'll work... */
@@ -109,26 +110,42 @@
       jdiv_round_up((long) cinfo->image_width, 8L);
     cinfo->output_height = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_height, 8L);
+#if JPEG_LIB_VERSION >= 70
+    cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = 1;
+#else
     cinfo->min_DCT_scaled_size = 1;
+#endif
   } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) {
     /* Provide 1/4 scaling */
     cinfo->output_width = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_width, 4L);
     cinfo->output_height = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_height, 4L);
+#if JPEG_LIB_VERSION >= 70
+    cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = 2;
+#else
     cinfo->min_DCT_scaled_size = 2;
+#endif
   } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) {
     /* Provide 1/2 scaling */
     cinfo->output_width = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_width, 2L);
     cinfo->output_height = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_height, 2L);
+#if JPEG_LIB_VERSION >= 70
+    cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = 4;
+#else
     cinfo->min_DCT_scaled_size = 4;
+#endif
   } else {
     /* Provide 1/1 scaling */
     cinfo->output_width = cinfo->image_width;
     cinfo->output_height = cinfo->image_height;
+#if JPEG_LIB_VERSION >= 70
+    cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = DCTSIZE;
+#else
     cinfo->min_DCT_scaled_size = DCTSIZE;
+#endif
   }
   /* In selecting the actual DCT scaling for each component, we try to
    * scale up the chroma components via IDCT scaling rather than upsampling.
@@ -137,15 +154,19 @@
    */
   for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
        ci++, compptr++) {
-    int ssize = cinfo->min_DCT_scaled_size;
+    int ssize = cinfo->_min_DCT_scaled_size;
     while (ssize < DCTSIZE &&
 	   (compptr->h_samp_factor * ssize * 2 <=
-	    cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) &&
+	    cinfo->max_h_samp_factor * cinfo->_min_DCT_scaled_size) &&
 	   (compptr->v_samp_factor * ssize * 2 <=
-	    cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) {
+	    cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size)) {
       ssize = ssize * 2;
     }
+#if JPEG_LIB_VERSION >= 70
+    compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
+#else
     compptr->DCT_scaled_size = ssize;
+#endif
   }
 
   /* Recompute downsampled dimensions of components;
@@ -156,11 +177,11 @@
     /* Size in samples, after IDCT scaling */
     compptr->downsampled_width = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_width *
-		    (long) (compptr->h_samp_factor * compptr->DCT_scaled_size),
+		    (long) (compptr->h_samp_factor * compptr->_DCT_scaled_size),
 		    (long) (cinfo->max_h_samp_factor * DCTSIZE));
     compptr->downsampled_height = (JDIMENSION)
       jdiv_round_up((long) cinfo->image_height *
-		    (long) (compptr->v_samp_factor * compptr->DCT_scaled_size),
+		    (long) (compptr->v_samp_factor * compptr->_DCT_scaled_size),
 		    (long) (cinfo->max_v_samp_factor * DCTSIZE));
   }
 
@@ -384,7 +405,11 @@
   jinit_inverse_dct(cinfo);
   /* Entropy decoding: either Huffman or arithmetic coding. */
   if (cinfo->arith_code) {
+#ifdef D_ARITH_CODING_SUPPORTED
+    jinit_arith_decoder(cinfo);
+#else
     ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
   } else {
     if (cinfo->progressive_mode) {
 #ifdef D_PROGRESSIVE_SUPPORTED
diff --git a/jdsample.c b/jdsample.c
index 4e0b8b4..1864dd6 100644
--- a/jdsample.c
+++ b/jdsample.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1991-1996, Thomas G. Lane.
  * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -23,6 +24,7 @@
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "jsimd.h"
+#include "jpegcomp.h"
 
 
 /* Pointer to routine to upsample a single component */
@@ -420,7 +422,7 @@
   /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1,
    * so don't ask for it.
    */
-  do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1;
+  do_fancy = cinfo->do_fancy_upsampling && cinfo->_min_DCT_scaled_size > 1;
 
   /* Verify we can handle the sampling factors, select per-component methods,
    * and create storage as needed.
@@ -430,10 +432,10 @@
     /* Compute size of an "input group" after IDCT scaling.  This many samples
      * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
      */
-    h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) /
-		 cinfo->min_DCT_scaled_size;
-    v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) /
-		 cinfo->min_DCT_scaled_size;
+    h_in_group = (compptr->h_samp_factor * compptr->_DCT_scaled_size) /
+		 cinfo->_min_DCT_scaled_size;
+    v_in_group = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
+		 cinfo->_min_DCT_scaled_size;
     h_out_group = cinfo->max_h_samp_factor;
     v_out_group = cinfo->max_v_samp_factor;
     upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
diff --git a/jdtrans.c b/jdtrans.c
index 6c0ab71..f0cd0ae 100644
--- a/jdtrans.c
+++ b/jdtrans.c
@@ -99,9 +99,18 @@
   /* This is effectively a buffered-image operation. */
   cinfo->buffered_image = TRUE;
 
+#if JPEG_LIB_VERSION >= 80
+  /* Compute output image dimensions and related values. */
+  jpeg_core_output_dimensions(cinfo);
+#endif
+
   /* Entropy decoding: either Huffman or arithmetic coding. */
   if (cinfo->arith_code) {
+#ifdef D_ARITH_CODING_SUPPORTED
+    jinit_arith_decoder(cinfo);
+#else
     ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
   } else {
     if (cinfo->progressive_mode) {
 #ifdef D_PROGRESSIVE_SUPPORTED
diff --git a/jerror.h b/jerror.h
index fc2fffe..275086e 100644
--- a/jerror.h
+++ b/jerror.h
@@ -2,6 +2,7 @@
  * jerror.h
  *
  * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -39,14 +40,23 @@
 JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
 
 /* For maintenance convenience, list is alphabetical by message code name */
+#if JPEG_LIB_VERSION < 70
 JMESSAGE(JERR_ARITH_NOTIMPL,
-	 "Sorry, there are legal restrictions on arithmetic coding")
+	 "Sorry, arithmetic coding is not implemented")
+#endif
 JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
 JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
 JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
 JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+#if JPEG_LIB_VERSION >= 70
+JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
+#endif
 JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
 JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
+#if JPEG_LIB_VERSION >= 70
+JMESSAGE(JERR_BAD_DROP_SAMPLING,
+	 "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
+#endif
 JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
 JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
 JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
@@ -93,6 +103,9 @@
 JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
 JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
 JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+#if JPEG_LIB_VERSION >= 70
+JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
+#endif
 JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
 JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
 JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
@@ -170,6 +183,9 @@
 JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
 JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
 JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+#if JPEG_LIB_VERSION >= 70
+JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
+#endif
 JMESSAGE(JWRN_BOGUS_PROGRESSION,
 	 "Inconsistent progression sequence for component %d coefficient %d")
 JMESSAGE(JWRN_EXTRANEOUS_DATA,
@@ -182,6 +198,13 @@
 	 "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
 JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
 JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+#if JPEG_LIB_VERSION < 70
+JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
+#if defined(C_ARITH_CODING_SUPPORTED) || defined(D_ARITH_CODING_SUPPORTED)
+JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
+JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
+#endif
+#endif
 
 #ifdef JMAKE_ENUM_LIST
 
diff --git a/jmemmgr.c b/jmemmgr.c
index 5458952..cf32524 100644
--- a/jmemmgr.c
+++ b/jmemmgr.c
@@ -37,6 +37,15 @@
 #endif
 
 
+LOCAL(size_t)
+round_up_pow2 (size_t a, size_t b)
+/* a rounded up to the next multiple of b, i.e. ceil(a/b)*b */
+/* Assumes a >= 0, b > 0, and b is a power of 2 */
+{
+  return ((a + b - 1) & (~(b - 1)));
+}
+
+
 /*
  * Some important notes:
  *   The allocation routines provided here must never return NULL.
@@ -265,7 +274,7 @@
    * and so that algorithms can straddle outside the proper area up
    * to the next alignment.
    */
-  sizeofobject = jround_up(sizeofobject, ALIGN_SIZE);
+  sizeofobject = round_up_pow2(sizeofobject, ALIGN_SIZE);
 
   /* Check for unsatisfiable request (do now to ensure no overflow below) */
   if ((SIZEOF(small_pool_hdr) + sizeofobject + ALIGN_SIZE - 1) > MAX_ALLOC_CHUNK)
@@ -354,7 +363,7 @@
    * algorithms can straddle outside the proper area up to the next
    * alignment.
    */
-  sizeofobject = jround_up(sizeofobject, ALIGN_SIZE);
+  sizeofobject = round_up_pow2(sizeofobject, ALIGN_SIZE);
 
   /* Check for unsatisfiable request (do now to ensure no overflow below) */
   if ((SIZEOF(large_pool_hdr) + sizeofobject + ALIGN_SIZE - 1) > MAX_ALLOC_CHUNK)
@@ -420,7 +429,7 @@
   /* Make sure each row is properly aligned */
   if ((ALIGN_SIZE % SIZEOF(JSAMPLE)) != 0)
     out_of_memory(cinfo, 5);	/* safety check */
-  samplesperrow = (JDIMENSION)jround_up(samplesperrow, (2 * ALIGN_SIZE) / SIZEOF(JSAMPLE));
+  samplesperrow = (JDIMENSION)round_up_pow2(samplesperrow, (2 * ALIGN_SIZE) / SIZEOF(JSAMPLE));
 
   /* Calculate max # of rows allowed in one allocation chunk */
   ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
diff --git a/jmorecfg.h b/jmorecfg.h
index 0e7fb72..c14a5f3 100644
--- a/jmorecfg.h
+++ b/jmorecfg.h
@@ -257,8 +257,6 @@
  * (You may HAVE to do that if your compiler doesn't like null source files.)
  */
 
-/* Arithmetic coding is unsupported for legal reasons.  Complaints to IBM. */
-
 /* Capability options common to encoder and decoder: */
 
 #define DCT_ISLOW_SUPPORTED	/* slow but accurate integer algorithm */
@@ -267,7 +265,6 @@
 
 /* Encoder capability options: */
 
-#undef  C_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */
 #define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
 #define C_PROGRESSIVE_SUPPORTED	    /* Progressive JPEG? (Requires MULTISCAN)*/
 #define ENTROPY_OPT_SUPPORTED	    /* Optimization of entropy coding parms? */
@@ -283,7 +280,6 @@
 
 /* Decoder capability options: */
 
-#undef  D_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */
 #define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
 #define D_PROGRESSIVE_SUPPORTED	    /* Progressive JPEG? (Requires MULTISCAN)*/
 #define SAVE_MARKERS_SUPPORTED	    /* jpeg_save_markers() needed? */
diff --git a/jpegcomp.h b/jpegcomp.h
new file mode 100644
index 0000000..1b9e0a4
--- /dev/null
+++ b/jpegcomp.h
@@ -0,0 +1,26 @@
+/*
+ * jpegcomp.h
+ *
+ * Copyright (C) 2010, D. R. Commander
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * JPEG compatibility macros
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+#if JPEG_LIB_VERSION >= 70
+#define _DCT_scaled_size DCT_h_scaled_size
+#define _min_DCT_scaled_size min_DCT_h_scaled_size
+#define _min_DCT_h_scaled_size min_DCT_h_scaled_size
+#define _min_DCT_v_scaled_size min_DCT_v_scaled_size
+#define _jpeg_width jpeg_width
+#define _jpeg_height jpeg_height
+#else
+#define _DCT_scaled_size DCT_scaled_size
+#define _min_DCT_scaled_size min_DCT_scaled_size
+#define _min_DCT_h_scaled_size min_DCT_scaled_size
+#define _min_DCT_v_scaled_size min_DCT_scaled_size
+#define _jpeg_width image_width
+#define _jpeg_height image_height
+#endif
diff --git a/jpegint.h b/jpegint.h
index 7a31f51..7871748 100644
--- a/jpegint.h
+++ b/jpegint.h
@@ -2,6 +2,7 @@
  * jpegint.h
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -304,6 +305,7 @@
 #define jinit_forward_dct	jIFDCT
 #define jinit_huff_encoder	jIHEncoder
 #define jinit_phuff_encoder	jIPHEncoder
+#define jinit_arith_encoder	jIAEncoder
 #define jinit_marker_writer	jIMWriter
 #define jinit_master_decompress	jIDMaster
 #define jinit_d_main_controller	jIDMainC
@@ -313,6 +315,7 @@
 #define jinit_marker_reader	jIMReader
 #define jinit_huff_decoder	jIHDecoder
 #define jinit_phuff_decoder	jIPHDecoder
+#define jinit_arith_decoder	jIADecoder
 #define jinit_inverse_dct	jIIDCT
 #define jinit_upsampler		jIUpsampler
 #define jinit_color_deconverter	jIDColor
@@ -327,6 +330,7 @@
 #define jzero_far		jZeroFar
 #define jpeg_zigzag_order	jZIGTable
 #define jpeg_natural_order	jZAGTable
+#define jpeg_aritab		jAriTab
 #endif /* NEED_SHORT_EXTERNAL_NAMES */
 
 
@@ -345,6 +349,7 @@
 EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
 EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
 EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo));
 EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
 /* Decompression module initialization routines */
 EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
@@ -358,6 +363,7 @@
 EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
 EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
 EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo));
 EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
 EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
 EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
@@ -369,7 +375,7 @@
 
 /* Utility routines in jutils.c */
 EXTERN(long) jdiv_round_up JPP((long a, long b));
-EXTERN(size_t) jround_up JPP((size_t a, size_t b));
+EXTERN(long) jround_up JPP((long a, long b));
 EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
 				    JSAMPARRAY output_array, int dest_row,
 				    int num_rows, JDIMENSION num_cols));
@@ -382,6 +388,9 @@
 #endif
 extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
 
+/* Arithmetic coding probability estimation tables in jaricom.c */
+extern const INT32 jpeg_aritab[];
+
 /* Suppress undefined-structure complaints if necessary. */
 
 #ifdef INCOMPLETE_TYPES_BROKEN
diff --git a/jpeglib.h b/jpeglib.h
index 7cc8039..cb3acaf 100644
--- a/jpeglib.h
+++ b/jpeglib.h
@@ -2,7 +2,8 @@
  * jpeglib.h
  *
  * Copyright (C) 1991-1998, Thomas G. Lane.
- * Copyright (C) 2009, D. R. Commander.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * Copyright (C) 2009-2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -14,10 +15,6 @@
 #ifndef JPEGLIB_H
 #define JPEGLIB_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * First we include the configuration files that record how this
  * installation of the JPEG library is set up.  jconfig.h can be
@@ -31,11 +28,11 @@
 #include "jmorecfg.h"		/* seldom changed options */
 
 
-/* Version ID for the JPEG library.
- * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
- */
-
-#define JPEG_LIB_VERSION  62	/* Version 6b */
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+extern "C" {
+#endif
+#endif
 
 
 /* Various constants determining the sizes of things.
@@ -149,12 +146,17 @@
    * Values of 1,2,4,8 are likely to be supported.  Note that different
    * components may receive different IDCT scalings.
    */
+#if JPEG_LIB_VERSION >= 70
+  int DCT_h_scaled_size;
+  int DCT_v_scaled_size;
+#else
   int DCT_scaled_size;
+#endif
   /* The downsampled dimensions are the component's actual, unpadded number
    * of samples at the main buffer (preprocessing/compression interface), thus
    * downsampled_width = ceil(image_width * Hi/Hmax)
    * and similarly for height.  For decompression, IDCT scaling is included, so
-   * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)
+   * downsampled_width = ceil(image_width * Hi/Hmax * DCT_[h_]scaled_size/DCTSIZE)
    */
   JDIMENSION downsampled_width;	 /* actual width in samples */
   JDIMENSION downsampled_height; /* actual height in samples */
@@ -169,7 +171,7 @@
   int MCU_width;		/* number of blocks per MCU, horizontally */
   int MCU_height;		/* number of blocks per MCU, vertically */
   int MCU_blocks;		/* MCU_width * MCU_height */
-  int MCU_sample_width;		/* MCU width in samples, MCU_width*DCT_scaled_size */
+  int MCU_sample_width;		/* MCU width in samples, MCU_width*DCT_[h_]scaled_size */
   int last_col_width;		/* # of non-dummy blocks across in last MCU */
   int last_row_height;		/* # of non-dummy blocks down in last MCU */
 
@@ -305,6 +307,19 @@
    * helper routines to simplify changing parameters.
    */
 
+#if JPEG_LIB_VERSION >= 70
+  unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+  JDIMENSION jpeg_width;	/* scaled JPEG image width */
+  JDIMENSION jpeg_height;	/* scaled JPEG image height */
+  /* Dimensions of actual JPEG image that will be written to file,
+   * derived from input dimensions by scaling factors above.
+   * These fields are computed by jpeg_start_compress().
+   * You can also use jpeg_calc_jpeg_dimensions() to determine these values
+   * in advance of calling jpeg_start_compress().
+   */
+#endif
+
   int data_precision;		/* bits of precision in image data */
 
   int num_components;		/* # of color components in JPEG image */
@@ -312,14 +327,19 @@
 
   jpeg_component_info * comp_info;
   /* comp_info[i] describes component that appears i'th in SOF */
-  
+
   JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
-  /* ptrs to coefficient quantization tables, or NULL if not defined */
-  
+#if JPEG_LIB_VERSION >= 70
+  int q_scale_factor[NUM_QUANT_TBLS];
+#endif
+  /* ptrs to coefficient quantization tables, or NULL if not defined,
+   * and corresponding scale factors (percentage, initialized 100).
+   */
+
   JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
   JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
   /* ptrs to Huffman coding tables, or NULL if not defined */
-  
+
   UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
   UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
   UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
@@ -335,6 +355,9 @@
   boolean arith_code;		/* TRUE=arithmetic coding, FALSE=Huffman */
   boolean optimize_coding;	/* TRUE=optimize entropy encoding parms */
   boolean CCIR601_sampling;	/* TRUE=first samples are cosited */
+#if JPEG_LIB_VERSION >= 70
+  boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */
+#endif
   int smoothing_factor;		/* 1..100, or 0 for no input smoothing */
   J_DCT_METHOD dct_method;	/* DCT algorithm selector */
 
@@ -378,6 +401,11 @@
   int max_h_samp_factor;	/* largest h_samp_factor */
   int max_v_samp_factor;	/* largest v_samp_factor */
 
+#if JPEG_LIB_VERSION >= 70
+  int min_DCT_h_scaled_size;	/* smallest DCT_h_scaled_size of any component */
+  int min_DCT_v_scaled_size;	/* smallest DCT_v_scaled_size of any component */
+#endif
+
   JDIMENSION total_iMCU_rows;	/* # of iMCU rows to be input to coef ctlr */
   /* The coefficient controller receives data in units of MCU rows as defined
    * for fully interleaved scans (whether the JPEG file is interleaved or not).
@@ -403,6 +431,12 @@
 
   int Ss, Se, Ah, Al;		/* progressive JPEG parameters for scan */
 
+#if JPEG_LIB_VERSION >= 80
+  int block_size;		/* the basic DCT block size: 1..16 */
+  const int * natural_order;	/* natural-order position array */
+  int lim_Se;			/* min( Se, DCTSIZE2-1 ) */
+#endif
+
   /*
    * Links to compression subobjects (methods and private variables of modules)
    */
@@ -549,6 +583,9 @@
   jpeg_component_info * comp_info;
   /* comp_info[i] describes component that appears i'th in SOF */
 
+#if JPEG_LIB_VERSION >= 80
+  boolean is_baseline;		/* TRUE if Baseline SOF0 encountered */
+#endif
   boolean progressive_mode;	/* TRUE if SOFn specifies progressive mode */
   boolean arith_code;		/* TRUE=arithmetic coding, FALSE=Huffman */
 
@@ -589,7 +626,12 @@
   int max_h_samp_factor;	/* largest h_samp_factor */
   int max_v_samp_factor;	/* largest v_samp_factor */
 
+#if JPEG_LIB_VERSION >= 70
+  int min_DCT_h_scaled_size;	/* smallest DCT_h_scaled_size of any component */
+  int min_DCT_v_scaled_size;	/* smallest DCT_v_scaled_size of any component */
+#else
   int min_DCT_scaled_size;	/* smallest DCT_scaled_size of any component */
+#endif
 
   JDIMENSION total_iMCU_rows;	/* # of iMCU rows in image */
   /* The coefficient controller's input and output progress is measured in
@@ -597,7 +639,7 @@
    * in fully interleaved JPEG scans, but are used whether the scan is
    * interleaved or not.  We define an iMCU row as v_samp_factor DCT block
    * rows of each component.  Therefore, the IDCT output contains
-   * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.
+   * v_samp_factor*DCT_[v_]scaled_size sample rows of a component per iMCU row.
    */
 
   JSAMPLE * sample_range_limit; /* table for fast range-limiting */
@@ -621,6 +663,14 @@
 
   int Ss, Se, Ah, Al;		/* progressive JPEG parameters for scan */
 
+#if JPEG_LIB_VERSION >= 80
+  /* These fields are derived from Se of first SOS marker.
+   */
+  int block_size;		/* the basic DCT block size: 1..16 */
+  const int * natural_order; /* natural-order position array for entropy decode */
+  int lim_Se;			/* min( Se, DCTSIZE2-1 ) for entropy decode */
+#endif
+
   /* This field is shared between entropy decoder and marker parser.
    * It is either zero or the code of a JPEG marker that has been
    * read from the data source, but has not yet been processed.
@@ -850,11 +900,18 @@
 #define jpeg_destroy_decompress	jDestDecompress
 #define jpeg_stdio_dest		jStdDest
 #define jpeg_stdio_src		jStdSrc
+#if JPEG_LIB_VERSION >= 80
+#define jpeg_mem_dest		jMemDest
+#define jpeg_mem_src		jMemSrc
+#endif
 #define jpeg_set_defaults	jSetDefaults
 #define jpeg_set_colorspace	jSetColorspace
 #define jpeg_default_colorspace	jDefColorspace
 #define jpeg_set_quality	jSetQuality
 #define jpeg_set_linear_quality	jSetLQuality
+#if JPEG_LIB_VERSION >= 70
+#define jpeg_default_qtables	jDefQTables
+#endif
 #define jpeg_add_quant_table	jAddQuantTable
 #define jpeg_quality_scaling	jQualityScaling
 #define jpeg_simple_progression	jSimProgress
@@ -864,6 +921,9 @@
 #define jpeg_start_compress	jStrtCompress
 #define jpeg_write_scanlines	jWrtScanlines
 #define jpeg_finish_compress	jFinCompress
+#if JPEG_LIB_VERSION >= 70
+#define jpeg_calc_jpeg_dimensions	jCjpegDimensions
+#endif
 #define jpeg_write_raw_data	jWrtRawData
 #define jpeg_write_marker	jWrtMarker
 #define jpeg_write_m_header	jWrtMHeader
@@ -880,6 +940,9 @@
 #define jpeg_input_complete	jInComplete
 #define jpeg_new_colormap	jNewCMap
 #define jpeg_consume_input	jConsumeInput
+#if JPEG_LIB_VERSION >= 80
+#define jpeg_core_output_dimensions	jCoreDimensions
+#endif
 #define jpeg_calc_output_dimensions	jCalcDimensions
 #define jpeg_save_markers	jSaveMarkers
 #define jpeg_set_marker_processor	jSetMarker
@@ -924,6 +987,16 @@
 EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
 EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
 
+#if JPEG_LIB_VERSION >= 80
+/* Data source and destination managers: memory buffers. */
+EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
+			       unsigned char ** outbuffer,
+			       unsigned long * outsize));
+EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,
+			      unsigned char * inbuffer,
+			      unsigned long insize));
+#endif
+
 /* Default parameter setup for compression */
 EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
 /* Compression parameter setup aids */
@@ -935,6 +1008,10 @@
 EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
 					  int scale_factor,
 					  boolean force_baseline));
+#if JPEG_LIB_VERSION >= 70
+EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo,
+				       boolean force_baseline));
+#endif
 EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
 				       const unsigned int *basic_table,
 				       int scale_factor,
@@ -954,12 +1031,17 @@
 					     JDIMENSION num_lines));
 EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));
 
+#if JPEG_LIB_VERSION >= 70
+/* Precalculate JPEG dimensions for current compression parameters. */
+EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo));
+#endif
+
 /* Replaces jpeg_write_scanlines when writing raw downsampled data. */
 EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,
 					    JSAMPIMAGE data,
 					    JDIMENSION num_lines));
 
-/* Write a special marker.  See libjpeg.doc concerning safe usage. */
+/* Write a special marker.  See libjpeg.txt concerning safe usage. */
 EXTERN(void) jpeg_write_marker
 	JPP((j_compress_ptr cinfo, int marker,
 	     const JOCTET * dataptr, unsigned int datalen));
@@ -1013,6 +1095,9 @@
 #define JPEG_SCAN_COMPLETED	4 /* Completed last iMCU row of a scan */
 
 /* Precalculate output dimensions for current decompression parameters. */
+#if JPEG_LIB_VERSION >= 80
+EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo));
+#endif
 EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
 
 /* Control saving of COM and APPn markers into marker_list. */
@@ -1108,7 +1193,9 @@
 #endif
 
 #ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
 }
 #endif
+#endif
 
 #endif /* JPEGLIB_H */
diff --git a/jpegtran.1 b/jpegtran.1
index 6de18e2..160b47d 100644
--- a/jpegtran.1
+++ b/jpegtran.1
@@ -1,4 +1,4 @@
-.TH JPEGTRAN 1 "3 August 1997"
+.TH JPEGTRAN 1 "31 January 2012"
 .SH NAME
 jpegtran \- lossless transformation of JPEG files
 .SH SYNOPSIS
@@ -60,6 +60,9 @@
 Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
 attached to the number.
 .TP
+.B \-arithmetic
+Use arithmetic coding.
+.TP
 .BI \-scans " file"
 Use the scan script given in the specified text file.
 .PP
@@ -117,7 +120,7 @@
 .TP
 .B \-trim
 Drop non-transformable edge blocks.
-.PP
+.IP
 Obviously, a transformation with
 .B \-trim
 is not reversible, so strictly speaking
@@ -130,12 +133,38 @@
 followed by
 .B \-rot 180 -trim
 trims both edges.
+.TP
+.B \-perfect
+If you are only interested in perfect transformations, add the
+.B \-perfect
+switch.  This causes
+.B jpegtran
+to fail with an error if the transformation is not perfect.
+.IP
+For example, you may want to do
+.IP
+.B (jpegtran \-rot 90 -perfect
+.I foo.jpg
+.B || djpeg
+.I foo.jpg
+.B | pnmflip \-r90 | cjpeg)
+.IP
+to do a perfect rotation, if available, or an approximated one if not.
+.TP
+.B \-crop WxH+X+Y
+Crop the image to a rectangular region of width W and height H, starting at
+point X,Y.  The lossless crop feature discards data outside of a given image
+region but losslessly preserves what is inside.  Like the rotate and flip
+transforms, lossless crop is restricted by the current JPEG format; the upper
+left corner of the selected region must fall on an iMCU boundary.  If it
+doesn't, then it is silently moved up and/or left to the nearest iMCU boundary
+(the lower right corner is unchanged.)
 .PP
-Another not-strictly-lossless transformation switch is:
+Other not-strictly-lossless transformation switches are:
 .TP
 .B \-grayscale
 Force grayscale output.
-.PP
+.IP
 This option discards the chrominance channels if the input image is YCbCr
 (ie, a standard color JPEG), resulting in a grayscale JPEG file.  The
 luminance channel is preserved exactly, so this is a better method of reducing
@@ -154,20 +183,16 @@
 comments and other excess baggage present in the source file.
 .TP
 .B \-copy comments
-Copy only comment markers.  This setting copies comments from the source file,
-but discards any other inessential data.
+Copy only comment markers.  This setting copies comments from the source file
+but discards any other data that is inessential for image display.
 .TP
 .B \-copy all
 Copy all extra markers.  This setting preserves miscellaneous markers
-found in the source file, such as JFIF thumbnails and Photoshop settings.
-In some files these extra markers can be sizable.
+found in the source file, such as JFIF thumbnails, Exif data, and Photoshop
+settings.  In some files, these extra markers can be sizable.
 .PP
-The default behavior is
-.BR "\-copy comments" .
-(Note: in IJG releases v6 and v6a,
-.B jpegtran
-always did the equivalent of
-.BR "\-copy none" .)
+The default behavior is \fB-copy comments\fR.  (Note: in IJG releases v6 and
+v6a, \fBjpegtran\fR always did the equivalent of \fB-copy none\fR.)
 .PP
 Additional switches recognized by jpegtran are:
 .TP
@@ -227,11 +252,11 @@
 .SH AUTHOR
 Independent JPEG Group
 .SH BUGS
-Arithmetic coding is not supported for legal reasons.
-.PP
 The transform options can't transform odd-size images perfectly.  Use
 .B \-trim
-if you don't like the results without it.
+or
+.B \-perfect
+if you don't like the results.
 .PP
 The entire image is read into memory and then written out again, even in
 cases where this isn't really necessary.  Expect swapping on large images,
diff --git a/jpegtran.c b/jpegtran.c
index 20ef111..40d4b6c 100644
--- a/jpegtran.c
+++ b/jpegtran.c
@@ -1,19 +1,21 @@
 /*
  * jpegtran.c
  *
- * Copyright (C) 1995-1997, Thomas G. Lane.
+ * Copyright (C) 1995-2010, Thomas G. Lane, Guido Vollbeding.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
  * This file contains a command-line user interface for JPEG transcoding.
- * It is very similar to cjpeg.c, but provides lossless transcoding between
- * different JPEG file formats.  It also provides some lossless and sort-of-
- * lossless transformations of JPEG data.
+ * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
+ * lossless transcoding between different JPEG file formats.  It also
+ * provides some lossless and sort-of-lossless transformations of JPEG data.
  */
 
 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
 #include "transupp.h"		/* Support routines for jpegtran */
 #include "jversion.h"		/* for version message */
+#include "config.h"
 
 #ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
 #ifdef __MWERKS__
@@ -62,24 +64,28 @@
 #ifdef C_PROGRESSIVE_SUPPORTED
   fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
 #endif
-#if TRANSFORMS_SUPPORTED
   fprintf(stderr, "Switches for modifying the image:\n");
+#if TRANSFORMS_SUPPORTED
+  fprintf(stderr, "  -crop WxH+X+Y  Crop to a rectangular subarea\n");
   fprintf(stderr, "  -grayscale     Reduce to grayscale (omit color data)\n");
   fprintf(stderr, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n");
+  fprintf(stderr, "  -perfect       Fail if there is non-transformable edge blocks\n");
   fprintf(stderr, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n");
+#endif
+#if TRANSFORMS_SUPPORTED
   fprintf(stderr, "  -transpose     Transpose image\n");
   fprintf(stderr, "  -transverse    Transverse transpose image\n");
   fprintf(stderr, "  -trim          Drop non-transformable edge blocks\n");
-#endif /* TRANSFORMS_SUPPORTED */
+#endif
   fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
+#endif
   fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
   fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
   fprintf(stderr, "  -outfile name  Specify name for output file\n");
   fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
   fprintf(stderr, "Switches for wizards:\n");
-#ifdef C_ARITH_CODING_SUPPORTED
-  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
-#endif
 #ifdef C_MULTISCAN_FILES_SUPPORTED
   fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
 #endif
@@ -132,8 +138,10 @@
   outfilename = NULL;
   copyoption = JCOPYOPT_DEFAULT;
   transformoption.transform = JXFORM_NONE;
+  transformoption.perfect = FALSE;
   transformoption.trim = FALSE;
   transformoption.force_grayscale = FALSE;
+  transformoption.crop = FALSE;
   cinfo->err->trace_level = 0;
 
   /* Scan command line options, adjust parameters */
@@ -160,7 +168,7 @@
       exit(EXIT_FAILURE);
 #endif
 
-    } else if (keymatch(arg, "copy", 1)) {
+    } else if (keymatch(arg, "copy", 2)) {
       /* Select which extra markers to copy. */
       if (++argn >= argc)	/* advance to next argument */
 	usage();
@@ -173,14 +181,31 @@
       } else
 	usage();
 
+    } else if (keymatch(arg, "crop", 2)) {
+      /* Perform lossless cropping. */
+#if TRANSFORMS_SUPPORTED
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
+	fprintf(stderr, "%s: bogus -crop argument '%s'\n",
+		progname, argv[argn]);
+	exit(EXIT_FAILURE);
+      }
+#else
+      select_transform(JXFORM_NONE);	/* force an error */
+#endif
+
     } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
       /* Enable debug printouts. */
       /* On first -d, print version identification */
       static boolean printed_version = FALSE;
 
       if (! printed_version) {
-	fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
-		JVERSION, JCOPYRIGHT);
+	fprintf(stderr, "%s version %s (build %s)\n",
+		PACKAGE_NAME, VERSION, BUILD);
+	fprintf(stderr, "%s\n\n", JCOPYRIGHT);
+	fprintf(stderr, "Emulating The Independent JPEG Group's libjpeg, version %s\n\n",
+		JVERSION);
 	printed_version = TRUE;
       }
       cinfo->err->trace_level++;
@@ -233,7 +258,12 @@
 	usage();
       outfilename = argv[argn];	/* save it away for later use */
 
-    } else if (keymatch(arg, "progressive", 1)) {
+    } else if (keymatch(arg, "perfect", 2)) {
+      /* Fail if there is any partial edge MCUs that the transform can't
+       * handle. */
+      transformoption.perfect = TRUE;
+
+    } else if (keymatch(arg, "progressive", 2)) {
       /* Select simple progressive mode. */
 #ifdef C_PROGRESSIVE_SUPPORTED
       simple_progressive = TRUE;
@@ -342,8 +372,10 @@
   jvirt_barray_ptr * src_coef_arrays;
   jvirt_barray_ptr * dst_coef_arrays;
   int file_index;
-  FILE * input_file;
-  FILE * output_file;
+  /* We assume all-in-memory processing and can therefore use only a
+   * single file pointer for sequential input and output operation. 
+   */
+  FILE * fp;
 
   /* On Mac, fetch a command line. */
 #ifdef USE_CCOMMAND
@@ -406,24 +438,13 @@
 
   /* Open the input file. */
   if (file_index < argc) {
-    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
-      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+    if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
       exit(EXIT_FAILURE);
     }
   } else {
     /* default input file is stdin */
-    input_file = read_stdin();
-  }
-
-  /* Open the output file. */
-  if (outfilename != NULL) {
-    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
-      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
-      exit(EXIT_FAILURE);
-    }
-  } else {
-    /* default output file is stdout */
-    output_file = write_stdout();
+    fp = read_stdin();
   }
 
 #ifdef PROGRESS_REPORT
@@ -431,7 +452,7 @@
 #endif
 
   /* Specify data source for decompression */
-  jpeg_stdio_src(&srcinfo, input_file);
+  jpeg_stdio_src(&srcinfo, fp);
 
   /* Enable saving of extra markers that we want to copy */
   jcopy_markers_setup(&srcinfo, copyoption);
@@ -443,7 +464,12 @@
    * jpeg_read_coefficients so that memory allocation will be done right.
    */
 #if TRANSFORMS_SUPPORTED
-  jtransform_request_workspace(&srcinfo, &transformoption);
+  /* Fail right away if -perfect is given and transformation is not perfect.
+   */
+  if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
+    fprintf(stderr, "%s: transformation is not perfect\n", progname);
+    exit(EXIT_FAILURE);
+  }
 #endif
 
   /* Read source file as DCT coefficients */
@@ -463,11 +489,32 @@
   dst_coef_arrays = src_coef_arrays;
 #endif
 
+  /* Close input file, if we opened it.
+   * Note: we assume that jpeg_read_coefficients consumed all input
+   * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
+   * only consume more while (! cinfo->inputctl->eoi_reached).
+   * We cannot call jpeg_finish_decompress here since we still need the
+   * virtual arrays allocated from the source object for processing.
+   */
+  if (fp != stdin)
+    fclose(fp);
+
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+    fp = write_stdout();
+  }
+
   /* Adjust default compression parameters by re-parsing the options */
   file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
 
   /* Specify data destination for compression */
-  jpeg_stdio_dest(&dstinfo, output_file);
+  jpeg_stdio_dest(&dstinfo, fp);
 
   /* Start compressor (note no image data is actually written here) */
   jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
@@ -488,11 +535,9 @@
   (void) jpeg_finish_decompress(&srcinfo);
   jpeg_destroy_decompress(&srcinfo);
 
-  /* Close files, if we opened them */
-  if (input_file != stdin)
-    fclose(input_file);
-  if (output_file != stdout)
-    fclose(output_file);
+  /* Close output file, if we opened it */
+  if (fp != stdout)
+    fclose(fp);
 
 #ifdef PROGRESS_REPORT
   end_progress_monitor((j_common_ptr) &dstinfo);
diff --git a/jpegut.c b/jpegut.c
index 37a744c..e46e97a 100644
--- a/jpegut.c
+++ b/jpegut.c
@@ -1,6 +1,6 @@
 /* Copyright (C)2004 Landmark Graphics Corporation
  * Copyright (C)2005 Sun Microsystems, Inc.
- * Copyright (C)2009 D. R. Commander
+ * Copyright (C)2009-2011 D. R. Commander
  *
  * This library is free software and may be redistributed and/or modified under
  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -18,34 +18,54 @@
 #include <string.h>
 #include "./rrtimer.h"
 #include "./turbojpeg.h"
+#ifndef _WIN32
+ #define stricmp strcasecmp
+#else
+ #include <time.h>
+ #define random() rand()
+#endif
 
 #define _catch(f) {if((f)==-1) {printf("TJPEG: %s\n", tjGetErrorStr());  bailout();}}
 
 const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
 const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
+const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
+const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
+
+enum {YUVENCODE=1, YUVDECODE};
+int yuv=0;
 
 int exitstatus=0;
 #define bailout() {exitstatus=-1;  goto finally;}
 
-int pixels[9][3]=
-{
-	{0, 255, 0},
-	{255, 0, 255},
-	{255, 255, 0},
-	{0, 0, 255},
-	{0, 255, 255},
-	{255, 0, 0},
-	{255, 255, 255},
-	{0, 0, 0},
-	{255, 0, 0}
-};
-
 void initbuf(unsigned char *buf, int w, int h, int ps, int flags)
 {
 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
 		_i, j;
 	if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
 	memset(buf, 0, w*h*ps);
+	if(ps==1)
+	{
+		for(_i=0; _i<16; _i++)
+		{
+			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+			for(j=0; j<w; j++)
+			{
+				if(((_i/8)+(j/8))%2==0) buf[w*i+j]=255;
+				else buf[w*i+j]=76;
+			}
+		}
+		for(_i=16; _i<h; _i++)
+		{
+			if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+			for(j=0; j<w; j++)
+			{
+				if(((_i/8)+(j/8))%2==0) buf[w*i+j]=0;
+				else buf[w*i+j]=226;
+			}
+		}
+		return;
+	}
 	for(_i=0; _i<16; _i++)
 	{
 		if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
@@ -77,6 +97,7 @@
 {
 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
 		j;
+	printf("\n");
 	for(i=0; i<h; i++)
 	{
 		for(j=0; j<w; j++)
@@ -93,6 +114,7 @@
 	int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
 		_i, j;
 	if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
+	if(ps==1) roffset=goffset=boffset=0;
 	if(subsamp==TJ_GRAYSCALE)
 	{
 		for(_i=0; _i<16; _i++)
@@ -174,6 +196,118 @@
 	return 1;
 }
 
+#define checkval(v, cv) { \
+	if(v<cv-1 || v>cv+1) { \
+		printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, i, j, cv, v); \
+		retval=0;  goto bailout; \
+	}}
+
+#define checkval0(v) { \
+	if(v>1) { \
+		printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, i, j, v); \
+		retval=0;  goto bailout; \
+	}}
+
+#define checkval255(v) { \
+	if(v<254) { \
+		printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, i, j, v); \
+		retval=0;  goto bailout; \
+	}}
+
+#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
+
+int checkbufyuv(unsigned char *buf, int w, int h, int subsamp)
+{
+	int i, j;
+	int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
+	int pw=PAD(w, hsf), ph=PAD(h, vsf);
+	int cw=pw/hsf, ch=ph/vsf;
+	int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
+	int retval=1;
+
+	for(i=0; i<16; i++)
+	{
+		for(j=0; j<pw; j++)
+		{
+			unsigned char y=buf[ypitch*i+j];
+			if(((i/8)+(j/8))%2==0) checkval255(y)
+			else checkval(y, 76)
+		}
+	}
+	for(i=16; i<ph; i++)
+	{
+		for(j=0; j<pw; j++)
+		{
+			unsigned char y=buf[ypitch*i+j];
+			if(((i/8)+(j/8))%2==0) checkval0(y)
+			else checkval(y, 226)
+		}
+	}
+	if(subsamp!=TJ_GRAYSCALE)
+	{
+		for(i=0; i<16/vsf; i++)
+		{
+			for(j=0; j<cw; j++)
+			{
+				unsigned char u=buf[ypitch*ph + (uvpitch*i+j)],
+					v=buf[ypitch*ph + uvpitch*ch + (uvpitch*i+j)];
+				if(((i*vsf/8)+(j*hsf/8))%2==0)
+				{
+					checkval(u, 128);  checkval(v, 128);
+				}
+				else
+				{
+					checkval(u, 85);  checkval255(v);
+				}
+			}
+		}
+		for(i=16/vsf; i<ch; i++)
+		{
+			for(j=0; j<cw; j++)
+			{
+				unsigned char u=buf[ypitch*ph + (uvpitch*i+j)],
+					v=buf[ypitch*ph + uvpitch*ch + (uvpitch*i+j)];
+				if(((i*vsf/8)+(j*hsf/8))%2==0)
+				{
+					checkval(u, 128);  checkval(v, 128);
+				}
+				else
+				{
+					checkval0(u);  checkval(v, 149);
+				}
+			}
+		}
+	}
+
+	bailout:
+	if(retval==0)
+	{
+		for(i=0; i<ph; i++)
+		{
+			for(j=0; j<pw; j++)
+				printf("%.3d ", buf[ypitch*i+j]);
+			printf("\n");
+		}
+		printf("\n");
+		for(i=0; i<ch; i++)
+		{
+			for(j=0; j<cw; j++)
+				printf("%.3d ", buf[ypitch*ph + (uvpitch*i+j)]);
+			printf("\n");
+		}
+		printf("\n");
+		for(i=0; i<ch; i++)
+		{
+			for(j=0; j<cw; j++)
+				printf("%.3d ", buf[ypitch*ph + uvpitch*ch + (uvpitch*i+j)]);
+			printf("\n");
+		}
+		printf("\n");
+	}
+
+	return retval;
+}
+
 void writejpeg(unsigned char *jpegbuf, unsigned long jpgbufsize, char *filename)
 {
 	FILE *outfile=NULL;
@@ -201,53 +335,86 @@
 	if(flags&TJ_BGR)
 	{
 		if(ps==3) pixformat="BGR";
-		else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
+		else {if(flags&TJ_ALPHAFIRST) pixformat="XBGR";  else pixformat="BGRX";}
 	}
 	else
 	{
 		if(ps==3) pixformat="RGB";
-		else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
+		else {if(flags&TJ_ALPHAFIRST) pixformat="XRGB";  else pixformat="RGBX";}
 	}
-	printf("%s %s -> %s Q%d ... ", pixformat,
-		(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp], qual);
+	if(ps==1) pixformat="Grayscale";
+	if(yuv==YUVENCODE)
+		printf("%s %s -> %s YUV ... ", pixformat,
+			(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp]);
+	else
+		printf("%s %s -> %s Q%d ... ", pixformat,
+			(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp], qual);
 
 	if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
 	{
 		printf("ERROR: Could not allocate buffer\n");  bailout();
 	}
 	initbuf(bmpbuf, w, h, ps, flags);
-	memset(jpegbuf, 0, TJBUFSIZE(w, h));
+	memset(jpegbuf, 0,
+		yuv==YUVENCODE? TJBUFSIZEYUV(w, h, subsamp):TJBUFSIZE(w, h));
 
 	t=rrtime();
-	_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
+	if(yuv==YUVENCODE)
+	{
+		_catch(tjEncodeYUV(hnd, bmpbuf, w, 0, h, ps, jpegbuf, subsamp, flags));
+		*size=TJBUFSIZEYUV(w, h, subsamp);
+	}
+	else
+	{
+		_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual,
+			flags));
+	}
 	t=rrtime()-t;
 
-	sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
-		(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
+	if(yuv==YUVENCODE)
+		sprintf(tempstr, "%s_enc_%s_%s_%s.yuv", basefilename, pixformat,
+			(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp]);
+	else
+		sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
+			(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
 	writejpeg(jpegbuf, *size, tempstr);
-	printf("Done.  %f ms\n  Result in %s\n", t*1000., tempstr);
+	if(yuv==YUVENCODE)
+	{
+		if(checkbufyuv(jpegbuf, w, h, subsamp)) printf("Passed.");
+		else {printf("FAILED!");  exitstatus=-1;}
+	}
+	else printf("Done.");
+	printf("  %f ms\n  Result in %s\n", t*1000., tempstr);
 
 	finally:
 	if(bmpbuf) free(bmpbuf);
 }
 
 void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
-	int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
+	int w, int h, int ps, char *basefilename, int subsamp, int flags)
 {
 	unsigned char *bmpbuf=NULL;
 	const char *pixformat;  int _w=0, _h=0;  double t;
+	unsigned long size=0;
+
+	if(yuv==YUVENCODE) return;
 
 	if(flags&TJ_BGR)
 	{
 		if(ps==3) pixformat="BGR";
-		else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
+		else {if(flags&TJ_ALPHAFIRST) pixformat="XBGR";  else pixformat="BGRX";}
 	}
 	else
 	{
 		if(ps==3) pixformat="RGB";
-		else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
+		else {if(flags&TJ_ALPHAFIRST) pixformat="XRGB";  else pixformat="RGBX";}
 	}
-	printf("JPEG -> %s %s ... ", pixformat, (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
+	if(ps==1) pixformat="Grayscale";
+	if(yuv==YUVDECODE)
+		printf("JPEG -> YUV %s ... ", _subnames[subsamp]);
+	else
+		printf("JPEG -> %s %s ... ", pixformat,
+			(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
 
 	_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
 	if(_w!=w || _h!=h)
@@ -255,19 +422,40 @@
 		printf("Incorrect JPEG header\n");  bailout();
 	}
 
-	if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
+	if(yuv==YUVDECODE) size=TJBUFSIZEYUV(w, h, subsamp);
+	else size=w*h*ps+1;
+	if((bmpbuf=(unsigned char *)malloc(size))==NULL)
 	{
 		printf("ERROR: Could not allocate buffer\n");  bailout();
 	}
-	memset(bmpbuf, 0, w*ps*h);
+	memset(bmpbuf, 0, size);
 
 	t=rrtime();
-	_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
+	if(yuv==YUVDECODE)
+	{
+		_catch(tjDecompressToYUV(hnd, jpegbuf, jpegsize, bmpbuf, flags));
+	}
+	else
+	{
+		_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps,
+			flags));
+	}
 	t=rrtime()-t;
 
-	if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
-	else {printf("FAILED!");  dumpbuf(bmpbuf, w, h, ps, flags);}
-
+	if(yuv==YUVDECODE)
+	{
+		if(checkbufyuv(bmpbuf, w, h, subsamp)) printf("Passed.");
+		else {printf("FAILED!");  exitstatus=-1;}
+	}
+	else
+	{
+		if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
+		else
+		{
+			printf("FAILED!");  exitstatus=-1;
+			dumpbuf(bmpbuf, w, h, ps, flags);
+		}
+	}
 	printf("  %f ms\n\n", t*1000.);
 
 	finally:
@@ -279,7 +467,8 @@
 	tjhandle hnd=NULL, dhnd=NULL;  unsigned char *jpegbuf=NULL;
 	unsigned long size;
 
-	if((jpegbuf=(unsigned char *)malloc(TJBUFSIZE(w, h))) == NULL)
+	size=(yuv==YUVENCODE? TJBUFSIZEYUV(w, h, subsamp):TJBUFSIZE(w, h));
+	if((jpegbuf=(unsigned char *)malloc(size)) == NULL)
 	{
 		puts("ERROR: Could not allocate buffer.");  bailout();
 	}
@@ -290,30 +479,32 @@
 		{printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr());  bailout();}
 
 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
-	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, 0);
+	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 0);
+
+	if(ps==1 || yuv==YUVDECODE) goto finally;
 
 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
-	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
+	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR);
 
 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
-	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
+	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BOTTOMUP);
 
 	gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
-	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
+	gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR|TJ_BOTTOMUP);
 
 	if(ps==4)
 	{
 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
-		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
+		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST);
 
 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
-		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
+		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR);
 
 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
-		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
+		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BOTTOMUP);
 
 		gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
-		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
+		gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
 	}
 
 	finally:
@@ -343,13 +534,12 @@
 				printf("Memory allocation failure\n");  bailout();
 			}
 			memset(bmpbuf, 0, i*j*4);
-			for(i2=0; i2<i*j; i2++)
+			for(i2=0; i2<i*j*4; i2++)
 			{
-				bmpbuf[i2*4]=pixels[i2%9][2];
-				bmpbuf[i2*4+1]=pixels[i2%9][1];
-				bmpbuf[i2*2+2]=pixels[i2%9][0];
+				if(random()<RAND_MAX/2) bmpbuf[i2]=0;
+				else bmpbuf[i2]=255;
 			}
-			_catch(tjCompress(hnd, bmpbuf, i, i*4, j, 4,
+			_catch(tjCompress(hnd, bmpbuf, i, 0, j, 4,
 				jpgbuf, &size, TJ_444, 100, TJ_BGR));
 			free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
 
@@ -360,10 +550,10 @@
 			}
 			for(i2=0; i2<j*i*4; i2++)
 			{
-				if(i2%2==0) bmpbuf[i2]=0xFF;
-				else bmpbuf[i2]=0;
+				if(random()<RAND_MAX/2) bmpbuf[i2]=0;
+				else bmpbuf[i2]=255;
 			}
-			_catch(tjCompress(hnd, bmpbuf, j, j*4, i, 4,
+			_catch(tjCompress(hnd, bmpbuf, j, 0, i, 4,
 				jpgbuf, &size, TJ_444, 100, TJ_BGR));
 			free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
 		}
@@ -377,11 +567,39 @@
 
 int main(int argc, char *argv[])
 {
-	dotest(35, 41, 3, TJ_444, "test");
-	dotest(35, 41, 4, TJ_444, "test");
-	dotest(35, 41, 3, TJ_GRAYSCALE, "test");
-	dotest(35, 41, 4, TJ_GRAYSCALE, "test");
-	dotest1();
+	int doyuv=0;
+	#ifdef _WIN32
+	srand((unsigned int)time(NULL));
+	#endif
+	if(argc>1 && !stricmp(argv[1], "-yuv")) doyuv=1;
+	if(doyuv) yuv=YUVENCODE;
+	dotest(35, 39, 3, TJ_444, "test");
+	dotest(39, 41, 4, TJ_444, "test");
+	if(doyuv)
+	{
+		dotest(41, 35, 3, TJ_422, "test");
+		dotest(35, 39, 4, TJ_422, "test");
+		dotest(39, 41, 3, TJ_420, "test");
+		dotest(41, 35, 4, TJ_420, "test");
+	}
+	dotest(35, 39, 1, TJ_GRAYSCALE, "test");
+	dotest(39, 41, 3, TJ_GRAYSCALE, "test");
+	dotest(41, 35, 4, TJ_GRAYSCALE, "test");
+	if(!doyuv) dotest1();
+	if(doyuv)
+	{
+		yuv=YUVDECODE;
+		dotest(48, 48, 3, TJ_444, "test");
+		dotest(35, 39, 3, TJ_444, "test");
+		dotest(48, 48, 3, TJ_422, "test");
+		dotest(39, 41, 3, TJ_422, "test");
+		dotest(48, 48, 3, TJ_420, "test");
+		dotest(41, 35, 3, TJ_420, "test");
+		dotest(48, 48, 3, TJ_GRAYSCALE, "test");
+		dotest(35, 39, 3, TJ_GRAYSCALE, "test");
+		dotest(48, 48, 1, TJ_GRAYSCALE, "test");
+		dotest(39, 41, 1, TJ_GRAYSCALE, "test");
+	}
 
 	return exitstatus;
 }
diff --git a/jpgtest.c b/jpgtest.c
new file mode 100644
index 0000000..cac5ce3
--- /dev/null
+++ b/jpgtest.c
@@ -0,0 +1,610 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005, 2006 Sun Microsystems, Inc.
+ * Copyright (C)2009-2011 D. R. Commander
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include "./bmp.h"
+#include "./rrutil.h"
+#include "./rrtimer.h"
+#include "./turbojpeg.h"
+
+#define _throw(op, err) {  \
+	printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err);  goto bailout;}
+#define _throwunix(m) _throw(m, strerror(errno))
+#define _throwtj(m) _throw(m, tjGetErrorStr())
+#define _throwbmp(m) _throw(m, bmpgeterr())
+
+#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
+
+enum {YUVENCODE=1, YUVDECODE};
+int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
+	decomponly=0, yuv=0;
+const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
+const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
+	TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
+const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
+const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
+const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
+const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"};
+const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
+const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
+
+void printsigfig(double val, int figs)
+{
+	char format[80];
+	double _l=log10(val);  int l;
+	if(_l<0.)
+	{
+		l=(int)fabs(_l);
+		sprintf(format, "%%%d.%df", figs+l+2, figs+l);
+	}
+	else
+	{
+		l=(int)_l+1;
+		if(figs<=l) sprintf(format, "%%.0f");
+		else sprintf(format, "%%%d.%df", figs+1, figs-l);
+	}	
+	printf(format, val);
+}
+
+void dotest(unsigned char *srcbuf, int w, int h, int pf, int bu,
+	int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
+{
+	char tempstr[1024];
+	FILE *outfile=NULL;  tjhandle hnd=NULL;
+	unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
+	double start, elapsed;
+	int jpgbufsize=0, i, j, tilesizex=w, tilesizey=h, numtilesx=1, numtilesy=1,
+		ITER;
+	unsigned long *comptilesize=NULL;
+	int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
+		|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
+		|(fastupsample?TJ_FASTUPSAMPLE:0);
+	int ps=_ps[pf], tilen;
+	int pitch=w*ps, yuvsize=0;
+
+	flags |= _flags[pf];
+	if(bu) flags |= TJ_BOTTOMUP;
+
+	if(yuv==YUVENCODE) yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
+	if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h+1))) == NULL)
+		_throwunix("allocating image buffer");
+
+	if(!quiet)
+	{
+		if(yuv==YUVENCODE)
+			printf(">>>>>  %s (%s) <--> YUV %s  <<<<<\n", _pfname[pf],
+				bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
+		else
+			printf(">>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n", _pfname[pf],
+				bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
+	}
+	if(yuv) dotile=0;
+	if(dotile) {tilesizex=tilesizey=4;}  else {tilesizex=w;  tilesizey=h;}
+
+	do
+	{
+		tilesizex*=2;  if(tilesizex>w) tilesizex=w;
+		tilesizey*=2;  if(tilesizey>h) tilesizey=h;
+		numtilesx=(w+tilesizex-1)/tilesizex;
+		numtilesy=(h+tilesizey-1)/tilesizey;
+		if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)*numtilesx*numtilesy)) == NULL
+		|| (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)*numtilesx*numtilesy)) == NULL)
+			_throwunix("allocating image buffers");
+		memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
+		for(i=0; i<numtilesx*numtilesy; i++)
+		{
+			if((jpegbuf[i]=(unsigned char *)malloc(
+				yuv==YUVENCODE? TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub)
+					: TJBUFSIZE(tilesizex, tilesizey))) == NULL)
+				_throwunix("allocating image buffers");
+		}
+
+		// Compression test
+		if(quiet==1) printf("%s\t%s\t%s\t%d\t",  _pfname[pf], bu?"BU":"TD",
+			_subnamel[jpegsub], qual);
+		for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
+		if((hnd=tjInitCompress())==NULL)
+			_throwtj("executing tjInitCompress()");
+		if(yuv==YUVENCODE)
+		{
+			if(tjEncodeYUV(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
+				jpegbuf[0], jpegsub, flags)==-1)
+				_throwtj("executing tjEncodeYUV()");
+			comptilesize[0]=TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub);
+		}
+		else if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
+			jpegbuf[0], &comptilesize[0], jpegsub, qual, flags)==-1)
+			_throwtj("executing tjCompress()");
+		ITER=0;
+		start=rrtime();
+		do
+		{
+			jpgbufsize=0;  tilen=0;
+			for(i=0; i<h; i+=tilesizey)
+			{
+				for(j=0; j<w; j+=tilesizex)
+				{
+					int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
+					if(yuv==YUVENCODE)
+					{
+						if(tjEncodeYUV(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
+							temph, ps, jpegbuf[tilen], jpegsub, flags)==-1)
+							_throwtj("executing tjEncodeYUV()");
+						comptilesize[tilen]=TJBUFSIZEYUV(tempw, temph, jpegsub);
+					}
+					else if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
+						temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
+						flags)==-1)
+						_throwtj("executing tjCompress()");
+					jpgbufsize+=comptilesize[tilen];
+					tilen++;
+				}
+			}
+			ITER++;
+		} while((elapsed=rrtime()-start)<5.);
+		if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
+		hnd=NULL;
+		if(quiet==1)
+		{
+			if(tilesizex==w && tilesizey==h) printf("Full     \t");
+			else printf("%-4d %-4d\t", tilesizex, tilesizey);
+		}
+		if(quiet)
+		{
+			printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
+			printf("%c", quiet==2? '\n':'\t');
+			printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
+			printf("%c", quiet==2? '\n':'\t');
+		}
+		else
+		{
+			if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
+			else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
+			printf("C--> Frame rate:           %f fps\n", (double)ITER/elapsed);
+			printf("     Output image size:    %d bytes\n", jpgbufsize);
+			printf("     Compression ratio:    %f:1\n",
+				(double)(w*h*ps)/(double)jpgbufsize);
+			printf("     Source throughput:    %f Megapixels/sec\n",
+				(double)(w*h)/1000000.*(double)ITER/elapsed);
+			printf("     Output bit stream:    %f Megabits/sec\n",
+				(double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
+		}
+		if(tilesizex==w && tilesizey==h)
+		{
+			if(yuv==YUVENCODE)
+				sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
+			else
+				sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
+			if((outfile=fopen(tempstr, "wb"))==NULL)
+				_throwunix("opening reference image");
+			if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
+				_throwunix("writing reference image");
+			fclose(outfile);  outfile=NULL;
+			if(!quiet) printf("Reference image written to %s\n", tempstr);
+		}
+		if(yuv==YUVENCODE)
+		{
+			if(quiet==1) printf("\n");  goto bailout;
+		}
+
+		// Decompression test
+		memset(rgbbuf, 127, max(yuvsize, pitch*h));  // Grey image means decompressor did nothing
+		if((hnd=tjInitDecompress())==NULL)
+			_throwtj("executing tjInitDecompress()");
+		if(yuv==YUVDECODE)
+		{
+			if(tjDecompressToYUV(hnd, jpegbuf[0], jpgbufsize, rgbbuf, flags)==-1)
+				_throwtj("executing tjDecompressToYUV()");
+		}
+		else if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
+			tilesizey, ps, flags)==-1)
+			_throwtj("executing tjDecompress()");
+		ITER=0;
+		start=rrtime();
+		do
+		{
+			int tilen=0;
+			for(i=0; i<h; i+=tilesizey)
+			{
+				for(j=0; j<w; j+=tilesizex)
+				{
+					int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
+					if(yuv==YUVDECODE)
+					{
+						if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
+							&rgbbuf[pitch*i+ps*j], flags)==-1)
+							_throwtj("executing tjDecompressToYUV()");
+					}
+					else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
+						&rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
+						_throwtj("executing tjDecompress()");
+					tilen++;
+				}
+			}
+			ITER++;
+		}	while((elapsed=rrtime()-start)<5.);
+		if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
+		hnd=NULL;
+		if(quiet)
+		{
+			printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
+			printf("\n");
+		}
+		else
+		{
+			printf("D--> Frame rate:           %f fps\n", (double)ITER/elapsed);
+			printf("     Dest. throughput:     %f Megapixels/sec\n",
+				(double)(w*h)/1000000.*(double)ITER/elapsed);
+		}
+		if(yuv==YUVDECODE)
+		{
+			sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
+			if((outfile=fopen(tempstr, "wb"))==NULL)
+				_throwunix("opening YUV image for output");
+			if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
+				_throwunix("writing YUV image");
+			fclose(outfile);  outfile=NULL;
+		}
+		else
+		{
+			if(tilesizex==w && tilesizey==h)
+				sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
+					useppm?"ppm":"bmp");
+			else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
+				qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
+			if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
+				_throwbmp("saving bitmap");
+			sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
+			if(!quiet)
+				printf("Computing compression error and saving to %s.\n", tempstr);
+			if(jpegsub==TJ_GRAYSCALE)
+			{
+				for(j=0; j<h; j++)
+				{
+					for(i=0; i<w*ps; i+=ps)
+					{
+						int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
+							+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
+							+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
+						if(y>255) y=255;  if(y<0) y=0;
+						rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
+						rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
+						rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
+					}
+				}
+			}		
+			else
+			{
+				for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
+					rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
+			}
+			if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
+				_throwbmp("saving bitmap");
+		}
+
+		// Cleanup
+		if(outfile) {fclose(outfile);  outfile=NULL;}
+		if(jpegbuf)
+		{
+			for(i=0; i<numtilesx*numtilesy; i++)
+				{if(jpegbuf[i]) free(jpegbuf[i]);  jpegbuf[i]=NULL;}
+			free(jpegbuf);  jpegbuf=NULL;
+		}
+		if(comptilesize) {free(comptilesize);  comptilesize=NULL;}
+	} while(tilesizex<w || tilesizey<h);
+
+	if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
+	return;
+
+	bailout:
+	if(outfile) {fclose(outfile);  outfile=NULL;}
+	if(jpegbuf)
+	{
+		for(i=0; i<numtilesx*numtilesy; i++)
+			{if(jpegbuf[i]) free(jpegbuf[i]);  jpegbuf[i]=NULL;}
+		free(jpegbuf);  jpegbuf=NULL;
+	}
+	if(comptilesize) {free(comptilesize);  comptilesize=NULL;}
+	if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
+	if(hnd) {tjDestroy(hnd);  hnd=NULL;}
+	return;
+}
+
+
+void dodecomptest(char *filename, int pf, int bu, int useppm,
+	int quiet)
+{
+	char tempstr[1024];
+	FILE *file=NULL;  tjhandle hnd=NULL;
+	unsigned char *jpegbuf=NULL, *rgbbuf=NULL;
+	double start, elapsed;
+	int w, h, ITER;
+	unsigned long jpgbufsize=0;
+	int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
+		|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
+		|(fastupsample?TJ_FASTUPSAMPLE:0);
+	int ps=_ps[pf], pitch, jpegsub=-1;
+	char *temp=NULL;
+	int yuvsize, bufsize;
+
+	flags |= _flags[pf];
+	if(bu) flags |= TJ_BOTTOMUP;
+
+	if((file=fopen(filename, "rb"))==NULL)
+		_throwunix("opening file");
+	if(fseek(file, 0, SEEK_END)<0 || (jpgbufsize=ftell(file))<0)
+		_throwunix("determining file size");
+	if((jpegbuf=(unsigned char *)malloc(jpgbufsize))==NULL)
+		_throwunix("allocating memory");
+	if(fseek(file, 0, SEEK_SET)<0)
+		_throwunix("setting file position");
+	if(fread(jpegbuf, jpgbufsize, 1, file)<1)
+		_throwunix("reading JPEG data");
+	fclose(file);  file=NULL;
+
+	temp=strrchr(filename, '.');
+	if(temp!=NULL) *temp='\0';
+
+	if((hnd=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()");
+	if(tjDecompressHeader2(hnd, jpegbuf, jpgbufsize, &w, &h, &jpegsub)==-1)
+		_throwtj("executing tjDecompressHeader2()");
+
+	yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
+
+	pitch=w*ps;
+
+	if(quiet==1)
+	{
+		printf("All performance values in Mpixels/sec\n\n");
+		printf("Bitmap\tBitmap\tImage Size\tDecomp\n"),
+		printf("Format\tOrder\t X    Y  \tPerf\n\n");
+		printf("%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD", w, h);
+	}
+
+	bufsize=(yuv==YUVDECODE? yuvsize:pitch*h);
+	if((rgbbuf=(unsigned char *)malloc(bufsize))==NULL)
+		_throwunix("allocating image buffer");
+
+	if(!quiet)
+	{
+		if(yuv==YUVDECODE)
+			printf(">>>>>  JPEG --> YUV %s  <<<<<\n", _subnamel[jpegsub]);
+		else
+			printf(">>>>>  JPEG --> %s (%s)  <<<<<\n", _pfname[pf],
+				bu?"Bottom-up":"Top-down");
+		printf("\nImage size: %d x %d\n", w, h);
+	}
+
+	memset(rgbbuf, 127, bufsize);  // Grey image means decompressor did nothing
+	if(yuv==YUVDECODE)
+	{
+		if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
+			_throwtj("executing tjDecompressToYUV()");
+	}
+	else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
+		flags)==-1)
+		_throwtj("executing tjDecompress()");
+	ITER=0;
+	start=rrtime();
+	do
+	{
+		if(yuv==YUVDECODE)
+		{
+			if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
+				_throwtj("executing tjDecompressToYUV()");
+		}
+		else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
+			flags)==-1)
+			_throwtj("executing tjDecompress()");
+		ITER++;
+	}	while((elapsed=rrtime()-start)<5.);
+	if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
+	hnd=NULL;
+	if(quiet)
+	{
+		printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
+		printf("\n");
+	}
+	else
+	{
+		printf("D--> Frame rate:           %f fps\n", (double)ITER/elapsed);
+		printf("     Dest. throughput:     %f Megapixels/sec\n",
+			(double)(w*h)/1000000.*(double)ITER/elapsed);
+	}
+	sprintf(tempstr, "%s_full.%s", filename, useppm?"ppm":"bmp");
+	if(yuv==YUVDECODE)
+	{
+		sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
+		if((file=fopen(tempstr, "wb"))==NULL)
+			_throwunix("opening YUV image for output");
+		if(fwrite(rgbbuf, yuvsize, 1, file)!=1)
+			_throwunix("writing YUV image");
+		fclose(file);  file=NULL;
+	}
+	else
+	{
+		if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
+			_throwbmp("saving bitmap");
+	}
+
+	bailout:
+	if(file) {fclose(file);  file=NULL;}
+	if(jpegbuf) {free(jpegbuf);  jpegbuf=NULL;}
+	if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
+	if(hnd) {tjDestroy(hnd);  hnd=NULL;}
+	return;
+}
+
+
+void usage(char *progname)
+{
+	printf("USAGE: %s <Inputfile (BMP|PPM))> <%% Quality>\n", progname);
+	printf("       %s <Inputfile (JPG))>\n\n", progname);
+	printf("       [-tile]\n");
+	printf("       Test performance of the codec when the image is encoded\n");
+	printf("       as separate tiles of varying sizes.\n\n");
+	printf("       [-forcemmx] [-forcesse] [-forcesse2] [-forcesse3]\n");
+	printf("       Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec\n\n");
+	printf("       [-rgb | -bgr | -rgbx | -bgrx | -xbgr | -xrgb]\n");
+	printf("       Test the specified color conversion path in the codec (default: BGR)\n\n");
+	printf("       [-fastupsample]\n");
+	printf("       Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
+	printf("       YUV decoding in libjpeg decompressor\n\n");
+	printf("       [-quiet]\n");
+	printf("       Output in tabular rather than verbose format\n\n");
+	printf("       [-yuvencode]\n");
+	printf("       Encode RGB input as planar YUV rather than compressing as JPEG\n\n");
+	printf("       [-yuvdecode]\n");
+	printf("       Decode JPEG image to planar YUV rather than RGB\n\n");
+	printf("       NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
+	printf("       test will be performed for all quality values in the range.\n");
+	exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+	unsigned char *bmpbuf=NULL;  int w, h, i, useppm=0;
+	int qual=-1, dotile=0, quiet=0, hiqual=-1;  char *temp;
+	int pf=BMP_BGR;
+	int bu=0, minarg=2;
+
+	if(argc<minarg) usage(argv[0]);
+
+	temp=strrchr(argv[1], '.');
+	if(temp!=NULL)
+	{
+		if(!stricmp(temp, ".ppm")) useppm=1;
+		if(!stricmp(temp, ".jpg") || !stricmp(temp, ".jpeg")) decomponly=1;
+	}
+
+	printf("\n");
+
+	if(argc>minarg)
+	{
+		for(i=minarg; i<argc; i++)
+		{
+			if(!stricmp(argv[i], "-yuvencode"))
+			{
+				printf("Testing YUV planar encoding\n\n");
+				yuv=YUVENCODE;  hiqual=qual=100;
+			}
+			if(!stricmp(argv[i], "-yuvdecode"))
+			{
+				printf("Testing YUV planar decoding\n\n");
+				yuv=YUVDECODE;
+			}
+		}
+	}
+
+	if(!decomponly && yuv!=YUVENCODE)
+	{
+		minarg=3;
+		if(argc<minarg) usage(argv[0]);
+		if((qual=atoi(argv[2]))<1 || qual>100)
+		{
+			puts("ERROR: Quality must be between 1 and 100.");
+			exit(1);
+		}
+		if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
+			&& sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
+			&& hiqual<=100) {}
+		else hiqual=qual;
+	}
+
+	if(argc>minarg)
+	{
+		for(i=minarg; i<argc; i++)
+		{
+			if(!stricmp(argv[i], "-tile")) dotile=1;
+			if(!stricmp(argv[i], "-forcesse3"))
+			{
+				printf("Using SSE3 code\n\n");
+				forcesse3=1;
+			}
+			if(!stricmp(argv[i], "-forcesse2"))
+			{
+				printf("Using SSE2 code\n\n");
+				forcesse2=1;
+			}
+			if(!stricmp(argv[i], "-forcesse"))
+			{
+				printf("Using SSE code\n\n");
+				forcesse=1;
+			}
+			if(!stricmp(argv[i], "-forcemmx"))
+			{
+				printf("Using MMX code\n\n");
+				forcemmx=1;
+			}
+			if(!stricmp(argv[i], "-fastupsample"))
+			{
+				printf("Using fast upsampling code\n\n");
+				fastupsample=1;
+			}
+			if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
+			if(!stricmp(argv[i], "-rgbx")) pf=BMP_RGBX;
+			if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
+			if(!stricmp(argv[i], "-bgrx")) pf=BMP_BGRX;
+			if(!stricmp(argv[i], "-xbgr")) pf=BMP_XBGR;
+			if(!stricmp(argv[i], "-xrgb")) pf=BMP_XRGB;
+			if(!stricmp(argv[i], "-bottomup")) bu=1;
+			if(!stricmp(argv[i], "-quiet")) quiet=1;
+			if(!stricmp(argv[i], "-qq")) quiet=2;
+		}
+	}
+
+	if(!decomponly)
+	{
+		if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
+			_throwbmp("loading bitmap");
+		temp=strrchr(argv[1], '.');
+		if(temp!=NULL) *temp='\0';
+	}
+
+	if(quiet==1 && !decomponly)
+	{
+		printf("All performance values in Mpixels/sec\n\n");
+		printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
+		printf("Format\tOrder\tFormat\tQual\t X    Y  \tPerf \tRatio\tPerf\n\n");
+	}
+
+	if(decomponly)
+	{
+		dodecomptest(argv[1], pf, bu, 1, quiet);
+		printf("\n");
+		goto bailout;
+	}
+	for(i=hiqual; i>=qual; i--)
+		dotest(bmpbuf, w, h, pf, bu, TJ_GRAYSCALE, i, argv[1], dotile, useppm, quiet);
+	printf("\n");
+	for(i=hiqual; i>=qual; i--)
+		dotest(bmpbuf, w, h, pf, bu, TJ_420, i, argv[1], dotile, useppm, quiet);
+	printf("\n");
+	for(i=hiqual; i>=qual; i--)
+		dotest(bmpbuf, w, h, pf, bu, TJ_422, i, argv[1], dotile, useppm, quiet);
+	printf("\n");
+	for(i=hiqual; i>=qual; i--)
+		dotest(bmpbuf, w, h, pf, bu, TJ_444, i, argv[1], dotile, useppm, quiet);
+	printf("\n");
+
+	bailout:
+	if(bmpbuf) free(bmpbuf);
+	return 0;
+}
diff --git a/jpgtest.cxx b/jpgtest.cxx
deleted file mode 100644
index b1c5e1a..0000000
--- a/jpgtest.cxx
+++ /dev/null
@@ -1,392 +0,0 @@
-/* Copyright (C)2004 Landmark Graphics Corporation
- * Copyright (C)2005, 2006 Sun Microsystems, Inc.
- * Copyright (C)2009 D. R. Commander
- *
- * This library is free software and may be redistributed and/or modified under
- * the terms of the wxWindows Library License, Version 3.1 or (at your option)
- * any later version.  The full license is in the LICENSE.txt file included
- * with this distribution.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * wxWindows Library License for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "./bmp.h"
-#include "./rrutil.h"
-#include "./rrtimer.h"
-#include "./turbojpeg.h"
-
-#define _catch(f) {if((f)==-1) {printf("Error in %s:\n%s\n", #f, tjGetErrorStr());  goto bailout;}}
-
-int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0;
-const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
-const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
-	TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
-const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
-const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
-const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
-const char *_pfname[]={"RGB", "RGBA", "BGR", "BGRA", "ABGR", "ARGB"};
-const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
-const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
-
-void printsigfig(double val, int figs)
-{
-	char format[80];
-	double _l=log10(val);  int l;
-	if(_l<0.)
-	{
-		l=(int)fabs(_l);
-		sprintf(format, "%%%d.%df", figs+l+2, figs+l);
-	}
-	else
-	{
-		l=(int)_l+1;
-		if(figs<=l) sprintf(format, "%%.0f");
-		else sprintf(format, "%%%d.%df", figs+1, figs-l);
-	}	
-	printf(format, val);
-}
-
-void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
-	int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
-{
-	char tempstr[1024];
-	FILE *outfile;  tjhandle hnd;
-	unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
-	rrtimer timer; double elapsed;
-	int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
-	unsigned long *comptilesize=NULL;
-	int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
-		|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
-		|(fastupsample?TJ_FASTUPSAMPLE:0);
-	int ps=_ps[pf];
-	int pitch=w*ps;
-
-	flags |= _flags[pf];
-	if(bu) flags |= TJ_BOTTOMUP;
-
-	if((rgbbuf=(unsigned char *)malloc(pitch*h)) == NULL)
-	{
-		puts("ERROR: Could not allocate image buffer.");
-		exit(1);
-	}
-
-	if(!quiet) printf("\n>>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n", _pfname[pf],
-		bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
-	if(dotile) {tilesizex=tilesizey=4;}  else {tilesizex=w;  tilesizey=h;}
-
-	do
-	{
-		tilesizex*=2;  if(tilesizex>w) tilesizex=w;
-		tilesizey*=2;  if(tilesizey>h) tilesizey=h;
-		numtilesx=(w+tilesizex-1)/tilesizex;
-		numtilesy=(h+tilesizey-1)/tilesizey;
-		if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)*numtilesx*numtilesy)) == NULL
-		|| (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)*numtilesx*numtilesy)) == NULL)
-		{
-			puts("ERROR: Could not allocate image buffers.");
-			goto bailout;
-		}
-		memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
-		for(i=0; i<numtilesx*numtilesy; i++)
-		{
-			if((jpegbuf[i]=(unsigned char *)malloc(TJBUFSIZE(tilesizex, tilesizey))) == NULL)
-			{
-				puts("ERROR: Could not allocate image buffers.");
-				goto bailout;
-			}
-		}
-
-		// Compression test
-		if(quiet) printf("%s\t%s\t%s\t%d\t",  _pfname[pf], bu?"BU":"TD",
-			_subnamel[jpegsub], qual);
-		for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
-		if((hnd=tjInitCompress())==NULL)
-		{
-			printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());
-			goto bailout;
-		}
-		_catch(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
-			jpegbuf[0], &comptilesize[0], jpegsub, qual, flags));
-		ITER=0;
-		timer.start();
-		do
-		{
-			jpgbufsize=0;  int tilen=0;
-			for(i=0; i<h; i+=tilesizey)
-			{
-				for(j=0; j<w; j+=tilesizex)
-				{
-					int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
-					_catch(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
-						temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
-						flags));
-					jpgbufsize+=comptilesize[tilen];
-					tilen++;
-				}
-			}
-			ITER++;
-		} while((elapsed=timer.elapsed())<5.);
-		_catch(tjDestroy(hnd));
-		if(quiet)
-		{
-			if(tilesizex==w && tilesizey==h) printf("Full     \t");
-			else printf("%-4d %-4d\t", tilesizex, tilesizey);
-			printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
-			printf("\t");
-			printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
-			printf("\t");
-		}
-		else
-		{
-			if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
-			else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
-			printf("C--> Frame rate:           %f fps\n", (double)ITER/elapsed);
-			printf("     Output image size:    %d bytes\n", jpgbufsize);
-			printf("     Compression ratio:    %f:1\n",
-				(double)(w*h*ps)/(double)jpgbufsize);
-			printf("     Source throughput:    %f Megapixels/sec\n",
-				(double)(w*h)/1000000.*(double)ITER/elapsed);
-			printf("     Output bit stream:    %f Megabits/sec\n",
-				(double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
-		}
-		if(tilesizex==w && tilesizey==h)
-		{
-			sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
-			if((outfile=fopen(tempstr, "wb"))==NULL)
-			{
-				puts("ERROR: Could not open reference image");
-				exit(1);
-			}
-			if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
-			{
-				puts("ERROR: Could not write reference image");
-				exit(1);
-			}
-			fclose(outfile);
-			if(!quiet) printf("Reference image written to %s\n", tempstr);
-		}
-
-		// Decompression test
-		memset(rgbbuf, 127, pitch*h);  // Grey image means decompressor did nothing
-		if((hnd=tjInitDecompress())==NULL)
-		{
-			printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr());
-			goto bailout;
-		}
-		_catch(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
-			tilesizey, ps, flags));
-		ITER=0;
-		timer.start();
-		do
-		{
-			int tilen=0;
-			for(i=0; i<h; i+=tilesizey)
-			{
-				for(j=0; j<w; j+=tilesizex)
-				{
-					int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
-					_catch(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
-						&rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags));
-					tilen++;
-				}
-			}
-			ITER++;
-		}	while((elapsed=timer.elapsed())<5.);
-		_catch(tjDestroy(hnd));
-		if(quiet)
-		{
-			printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
-			printf("\n");
-		}
-		else
-		{
-			printf("D--> Frame rate:           %f fps\n", (double)ITER/elapsed);
-			printf("     Dest. throughput:     %f Megapixels/sec\n",
-				(double)(w*h)/1000000.*(double)ITER/elapsed);
-		}
-		if(tilesizex==w && tilesizey==h)
-			sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
-				useppm?"ppm":"bmp");
-		else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
-			qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
-		if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
-		{
-			printf("ERROR saving bitmap: %s\n", bmpgeterr());
-			goto bailout;
-		}
-		sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
-		if(!quiet)
-			printf("Computing compression error and saving to %s.\n", tempstr);
-		if(jpegsub==TJ_GRAYSCALE)
-		{
-			for(j=0; j<h; j++)
-			{
-				for(i=0; i<w*ps; i+=ps)
-				{
-					int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
-						+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
-						+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
-					if(y>255) y=255;  if(y<0) y=0;
-					rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
-					rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
-					rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
-				}
-			}
-		}		
-		else
-		{
-			for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
-				rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
-		}
-		if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
-		{
-			printf("ERROR saving bitmap: %s\n", bmpgeterr());
-			goto bailout;
-		}
-
-		// Cleanup
-		if(jpegbuf)
-		{
-			for(i=0; i<numtilesx*numtilesy; i++)
-				{if(jpegbuf[i]) free(jpegbuf[i]);  jpegbuf[i]=NULL;}
-			free(jpegbuf);  jpegbuf=NULL;
-		}
-		if(comptilesize) {free(comptilesize);  comptilesize=NULL;}
-	} while(tilesizex<w || tilesizey<h);
-
-	if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
-	return;
-
-	bailout:
-	if(jpegbuf)
-	{
-		for(i=0; i<numtilesx*numtilesy; i++)
-			{if(jpegbuf[i]) free(jpegbuf[i]);  jpegbuf[i]=NULL;}
-		free(jpegbuf);  jpegbuf=NULL;
-	}
-	if(comptilesize) {free(comptilesize);  comptilesize=NULL;}
-	if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
-	return;
-}
-
-
-int main(int argc, char *argv[])
-{
-	unsigned char *bmpbuf=NULL;  int w, h, i, useppm=0;
-	int qual, dotile=0, quiet=0, hiqual=-1;  char *temp;
-	BMPPIXELFORMAT pf=BMP_BGR;
-	int bu=0;
-
-	printf("\n");
-
-	if(argc<3)
-	{
-		printf("USAGE: %s <Inputfile (BMP|PPM)> <%% Quality>\n\n", argv[0]);
-		printf("       [-tile]\n");
-		printf("       Test performance of the codec when the image is encoded\n");
-		printf("       as separate tiles of varying sizes.\n\n");
-		printf("       [-forcemmx] [-forcesse] [-forcesse2] [-forcesse3]\n");
-		printf("       Force MMX, SSE, or SSE2 code paths in Intel codec\n\n");
-		printf("       [-rgb | -bgr | -rgba | -bgra | -abgr | -argb]\n");
-		printf("       Test the specified color conversion path in the codec (default: BGR)\n\n");
-		printf("       [-fastupsample]\n");
-		printf("       Use fast, inaccurate upsampling code to perform 4:2:2 and 4:2:0\n");
-		printf("       YUV decoding in libjpeg decompressor\n\n");
-		printf("       [-quiet]\n");
-		printf("       Output in tabular rather than verbose format\n\n");
-		printf("       NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
-		printf("       test will be performed for all quality values in the range.\n");
-		exit(1);
-	}
-	if((qual=atoi(argv[2]))<1 || qual>100)
-	{
-		puts("ERROR: Quality must be between 1 and 100.");
-		exit(1);
-	}
-	if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
-		&& sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
-		&& hiqual<=100) {}
-	else hiqual=qual;
-
-	if(argc>3)
-	{
-		for(i=3; i<argc; i++)
-		{
-			if(!stricmp(argv[i], "-tile")) dotile=1;
-			if(!stricmp(argv[i], "-forcesse3"))
-			{
-				printf("Using SSE3 code\n");
-				forcesse3=1;
-			}
-			if(!stricmp(argv[i], "-forcesse2"))
-			{
-				printf("Using SSE2 code\n");
-				forcesse2=1;
-			}
-			if(!stricmp(argv[i], "-forcesse"))
-			{
-				printf("Using SSE code\n");
-				forcesse=1;
-			}
-			if(!stricmp(argv[i], "-forcemmx"))
-			{
-				printf("Using MMX code\n");
-				forcemmx=1;
-			}
-			if(!stricmp(argv[i], "-fastupsample"))
-			{
-				printf("Using fast upsampling code\n");
-				fastupsample=1;
-			}
-			if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
-			if(!stricmp(argv[i], "-rgba")) pf=BMP_RGBA;
-			if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
-			if(!stricmp(argv[i], "-bgra")) pf=BMP_BGRA;
-			if(!stricmp(argv[i], "-abgr")) pf=BMP_ABGR;
-			if(!stricmp(argv[i], "-argb")) pf=BMP_ARGB;
-			if(!stricmp(argv[i], "-bottomup")) bu=1;
-			if(!stricmp(argv[i], "-quiet")) quiet=1;
-		}
-	}
-
-	if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
-	{
-		printf("ERROR loading bitmap: %s\n", bmpgeterr());  exit(1);
-	}
-
-	temp=strrchr(argv[1], '.');
-	if(temp!=NULL)
-	{
-		if(!stricmp(temp, ".ppm")) useppm=1;
-		*temp='\0';
-	}
-
-	if(quiet)
-	{
-		printf("All performance values in Mpixels/sec\n\n");
-		printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
-		printf("Format\tOrder\tFormat\tQual\t X    Y  \tPerf \tRatio\tPerf\n\n");
-	}
-
-	for(i=hiqual; i>=qual; i--)
-		dotest(bmpbuf, w, h, pf, bu, TJ_GRAYSCALE, i, argv[1], dotile, useppm, quiet);
-	if(quiet) printf("\n");
-	for(i=hiqual; i>=qual; i--)
-		dotest(bmpbuf, w, h, pf, bu, TJ_420, i, argv[1], dotile, useppm, quiet);
-	if(quiet) printf("\n");
-	for(i=hiqual; i>=qual; i--)
-		dotest(bmpbuf, w, h, pf, bu, TJ_422, i, argv[1], dotile, useppm, quiet);
-	if(quiet) printf("\n");
-	for(i=hiqual; i>=qual; i--)
-		dotest(bmpbuf, w, h, pf, bu, TJ_444, i, argv[1], dotile, useppm, quiet);
-
-	if(bmpbuf) free(bmpbuf);
-	return 0;
-}
diff --git a/jutils.c b/jutils.c
index 98b54f5..d18a955 100644
--- a/jutils.c
+++ b/jutils.c
@@ -77,8 +77,8 @@
 }
 
 
-GLOBAL(size_t)
-jround_up (size_t a, size_t b)
+GLOBAL(long)
+jround_up (long a, long b)
 /* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
 /* Assumes a >= 0, b > 0 */
 {
diff --git a/jversion.h b/jversion.h
index 6472c58..a4bd04f 100644
--- a/jversion.h
+++ b/jversion.h
@@ -1,7 +1,8 @@
 /*
  * jversion.h
  *
- * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding.
+ * Copyright (C) 2010, 2012, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -9,6 +10,23 @@
  */
 
 
+#if JPEG_LIB_VERSION >= 80
+
+#define JVERSION	"8b  16-May-2010"
+
+#elif JPEG_LIB_VERSION >= 70
+
+#define JVERSION        "7  27-Jun-2009"
+
+#else
+
 #define JVERSION	"6b  27-Mar-1998"
 
-#define JCOPYRIGHT	"Copyright (C) 1998, Thomas G. Lane"
+#endif
+
+#define JCOPYRIGHT	"Copyright (C) 1991-2010 Thomas G. Lane, Guido Vollbeding\n" \
+			"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
+			"Copyright (C) 2004 Landmark Graphics Corporation\n" \
+			"Copyright (C) 2005-2007 Sun Microsystems, Inc.\n" \
+			"Copyright (C) 2009 Pierre Ossman for Cendio AB\n" \
+			"Copyright (C) 2009-2011 D. R. Commander"
diff --git a/libjpeg.map.in b/libjpeg.map.in
new file mode 100644
index 0000000..5443943
--- /dev/null
+++ b/libjpeg.map.in
@@ -0,0 +1,10 @@
+LIBJPEGTURBO_@JPEG_LIB_VERSION_DECIMAL@ {
+  local:
+    jsimd_*;
+    jconst_*;
+};
+
+LIBJPEG_@JPEG_LIB_VERSION_DECIMAL@ {
+  global:
+    *;
+};
diff --git a/libjpeg.doc b/libjpeg.txt
similarity index 97%
rename from libjpeg.doc
rename to libjpeg.txt
index 689b206..d350fc7 100644
--- a/libjpeg.doc
+++ b/libjpeg.txt
@@ -1,6 +1,6 @@
 USING THE IJG JPEG LIBRARY
 
-Copyright (C) 1994-1998, Thomas G. Lane.
+Copyright (C) 1994-2010, Thomas G. Lane, Guido Vollbeding, D. R. Commander.
 This file is part of the Independent JPEG Group's software.
 For conditions of distribution and use, see the accompanying README file.
 
@@ -93,7 +93,6 @@
 use.)  Unsupported ISO options include:
 	* Hierarchical storage
 	* Lossless JPEG
-	* Arithmetic entropy coding (unsupported for legal reasons)
 	* DNL marker
 	* Nonintegral subsampling ratios
 We support both 8- and 12-bit data precision, but this is a compile-time
@@ -750,7 +749,7 @@
 machines) and reference it at your link step.  If you use only half of the
 library (only compression or only decompression), only that much code will be
 included from the library, unless your linker is hopelessly brain-damaged.
-The supplied makefiles build libjpeg.a automatically (see install.doc).
+The supplied makefiles build libjpeg.a automatically (see install.txt).
 
 While you can build the JPEG library as a shared library if the whim strikes
 you, we don't really recommend it.  The trouble with shared libraries is that
@@ -850,6 +849,11 @@
 	can't be expressed as a simple scalar multiplier, in which case the
 	premise of this routine collapses.  Caveat user.
 
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+	[libjpeg v7+ API/ABI emulation only]
+	Set default quantization tables with linear q_scale_factor[] values
+	(see below).
+
 jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
 		      const unsigned int *basic_table,
 		      int scale_factor, boolean force_baseline)
@@ -972,6 +976,33 @@
 	routines will set up table slot 0 for luminance quality and table
 	slot 1 for chrominance.
 
+int q_scale_factor[NUM_QUANT_TBLS]
+	[libjpeg v7+ API/ABI emulation only]
+	Linear quantization scaling factors (0-100, default 100)
+	for use with jpeg_default_qtables().
+	See rdswitch.c and cjpeg.c for an example of usage.
+	Note that the q_scale_factor[] values use "linear" scales, so JPEG
+	quality levels chosen by the user must be converted to these scales
+	using jpeg_quality_scaling().  Here is an example that corresponds to
+	cjpeg -quality 90,70:
+
+		jpeg_set_defaults(cinfo);
+
+		/* Set luminance quality 90. */
+		cinfo->q_scale_factor[0] = jpeg_quality_scaling(90);
+		/* Set chrominance quality 70. */
+		cinfo->q_scale_factor[1] = jpeg_quality_scaling(70);
+
+		jpeg_default_qtables(cinfo, force_baseline);
+
+	CAUTION: Setting separate quality levels for chrominance and luminance
+	is mainly only useful if chrominance subsampling is disabled.  2x2
+	chrominance subsampling (AKA "4:2:0") is the default, but you can
+	explicitly disable subsampling as follows:
+
+		cinfo->comp_info[0].v_samp_factor = 1;
+		cinfo->comp_info[0].h_samp_factor = 1;
+
 JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]
 JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]
 	Pointers to Huffman coding tables, one per table slot, or NULL if
@@ -982,9 +1013,16 @@
 	by setting optimize_coding, as discussed above; there's seldom
 	any need to mess with providing your own Huffman tables.
 
-There are some additional cinfo fields which are not documented here
-because you currently can't change them; for example, you can't set
-arith_code TRUE because arithmetic coding is unsupported.
+
+[libjpeg v7+ API/ABI emulation only]
+The actual dimensions of the JPEG image that will be written to the file are
+given by the following fields.  These are computed from the input image
+dimensions and the compression parameters by jpeg_start_compress().  You can
+also call jpeg_calc_jpeg_dimensions() to obtain the values that will result
+from the current parameter settings.
+
+JDIMENSION jpeg_width		Actual dimensions of output image.
+JDIMENSION jpeg_height
 
 
 Per-component parameters are stored in the struct cinfo.comp_info[i] for
@@ -1374,21 +1412,22 @@
 
 The JPEG compression library sends its compressed data to a "destination
 manager" module.  The default destination manager just writes the data to a
-stdio stream, but you can provide your own manager to do something else.
-Similarly, the decompression library calls a "source manager" to obtain the
-compressed data; you can provide your own source manager if you want the data
-to come from somewhere other than a stdio stream.
+memory buffer or to a stdio stream, but you can provide your own manager to
+do something else.  Similarly, the decompression library calls a "source
+manager" to obtain the compressed data; you can provide your own source
+manager if you want the data to come from somewhere other than a memory
+buffer or a stdio stream.
 
 In both cases, compressed data is processed a bufferload at a time: the
 destination or source manager provides a work buffer, and the library invokes
 the manager only when the buffer is filled or emptied.  (You could define a
 one-character buffer to force the manager to be invoked for each byte, but
 that would be rather inefficient.)  The buffer's size and location are
-controlled by the manager, not by the library.  For example, if you desired to
-decompress a JPEG datastream that was all in memory, you could just make the
-buffer pointer and length point to the original data in memory.  Then the
-buffer-reload procedure would be invoked only if the decompressor ran off the
-end of the datastream, which would indicate an erroneous datastream.
+controlled by the manager, not by the library.  For example, the memory
+source manager just makes the buffer pointer and length point to the original
+data in memory.  In this case the buffer-reload procedure will be invoked
+only if the decompressor ran off the end of the datastream, which would
+indicate an erroneous datastream.
 
 The work buffer is defined as an array of datatype JOCTET, which is generally
 "char" or "unsigned char".  On a machine where char is not exactly 8 bits
@@ -1440,7 +1479,8 @@
 method pointers, and insert a pointer to the struct into the "dest" field of
 the JPEG compression object.  This can be done in-line in your setup code if
 you like, but it's probably cleaner to provide a separate routine similar to
-the jpeg_stdio_dest() routine of the supplied destination manager.
+the jpeg_stdio_dest() or jpeg_mem_dest() routines of the supplied destination
+managers.
 
 Decompression source managers follow a parallel design, but with some
 additional frammishes.  The source manager struct contains a pointer and count
@@ -1516,10 +1556,10 @@
 pointers, and insert a pointer to the struct into the "src" field of the JPEG
 decompression object.  This can be done in-line in your setup code if you
 like, but it's probably cleaner to provide a separate routine similar to the
-jpeg_stdio_src() routine of the supplied source manager.
+jpeg_stdio_src() or jpeg_mem_src() routines of the supplied source managers.
 
-For more information, consult the stdio source and destination managers
-in jdatasrc.c and jdatadst.c.
+For more information, consult the memory and stdio source and destination
+managers in jdatasrc.c and jdatadst.c.
 
 
 I/O suspension
@@ -2608,7 +2648,7 @@
 component.  The return value is a pointer to an array of virtual-array
 descriptors.  Each virtual array can be accessed directly using the JPEG
 memory manager's access_virt_barray method (see Memory management, below,
-and also read structure.doc's discussion of virtual array handling).  Or,
+and also read structure.txt's discussion of virtual array handling).  Or,
 for simple transcoding to a different JPEG file format, the array list can
 just be handed directly to jpeg_write_coefficients().
 
@@ -2752,7 +2792,7 @@
 -----------------
 
 This section covers some key facts about the JPEG library's built-in memory
-manager.  For more info, please read structure.doc's section about the memory
+manager.  For more info, please read structure.txt's section about the memory
 manager, and consult the source code if necessary.
 
 All memory and temporary file allocation within the library is done via the
@@ -2867,7 +2907,7 @@
 larger than a char, so it affects the surrounding application's image data.
 The sample applications cjpeg and djpeg can support 12-bit mode only for PPM
 and GIF file formats; you must disable the other file formats to compile a
-12-bit cjpeg or djpeg.  (install.doc has more information about that.)
+12-bit cjpeg or djpeg.  (install.txt has more information about that.)
 At present, a 12-bit library can handle *only* 12-bit images, not both
 precisions.  (If you need to include both 8- and 12-bit libraries in a single
 application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES
@@ -2920,7 +2960,7 @@
 
 The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of
 the popular system include file setups, and some not-so-popular ones too.
-See install.doc for configuration procedures.
+See install.txt for configuration procedures.
 
 The code is not dependent on the exact sizes of the C data types.  As
 distributed, we make the assumptions that
@@ -2959,7 +2999,7 @@
 characters.  However, global function names can be made unique in the
 first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES.
 
-More info about porting the code may be gleaned by reading jconfig.doc,
+More info about porting the code may be gleaned by reading jconfig.txt,
 jmorecfg.h, and jinclude.h.
 
 
diff --git a/rdbmp.c b/rdbmp.c
index f22dfa6..be32e43 100644
--- a/rdbmp.c
+++ b/rdbmp.c
@@ -2,6 +2,7 @@
  * rdbmp.c
  *
  * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2010 by Guido Vollbeding.
  * Modified 2011 by Siarhei Siamashka.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
@@ -178,10 +179,41 @@
 }
 
 
+METHODDEF(JDIMENSION)
+get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 32-bit pixels */
+{
+  bmp_source_ptr source = (bmp_source_ptr) sinfo;
+  JSAMPARRAY image_ptr;
+  register JSAMPROW inptr, outptr;
+  register JDIMENSION col;
+
+  /* Fetch next row from virtual array */
+  source->source_row--;
+  image_ptr = (*cinfo->mem->access_virt_sarray)
+    ((j_common_ptr) cinfo, source->whole_image,
+     source->source_row, (JDIMENSION) 1, FALSE);
+  /* Transfer data.  Note source values are in BGR order
+   * (even though Microsoft's own documents say the opposite).
+   */
+  inptr = image_ptr[0];
+  outptr = source->pub.buffer[0];
+  for (col = cinfo->image_width; col > 0; col--) {
+    outptr[2] = *inptr++;	/* can omit GETJSAMPLE() safely */
+    outptr[1] = *inptr++;
+    outptr[0] = *inptr++;
+    inptr++;			/* skip the 4th byte (Alpha channel) */
+    outptr += 3;
+  }
+
+  return 1;
+}
+
+
 /*
  * This method loads the image into whole_image during the first call on
  * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
- * get_8bit_row or get_24bit_row on subsequent calls.
+ * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
  */
 
 METHODDEF(JDIMENSION)
@@ -223,6 +255,9 @@
   case 24:
     source->pub.get_pixel_rows = get_24bit_row;
     break;
+  case 32:
+    source->pub.get_pixel_rows = get_32bit_row;
+    break;
   default:
     ERREXIT(cinfo, JERR_BMP_BADDEPTH);
   }
@@ -251,8 +286,8 @@
 			       (((INT32) UCH(array[offset+3])) << 24))
   INT32 bfOffBits;
   INT32 headerSize;
-  INT32 biWidth = 0;		/* initialize to avoid compiler warning */
-  INT32 biHeight = 0;
+  INT32 biWidth;
+  INT32 biHeight;
   unsigned int biPlanes;
   INT32 biCompression;
   INT32 biXPelsPerMeter,biYPelsPerMeter;
@@ -300,8 +335,6 @@
       ERREXIT(cinfo, JERR_BMP_BADDEPTH);
       break;
     }
-    if (biPlanes != 1)
-      ERREXIT(cinfo, JERR_BMP_BADPLANES);
     break;
   case 40:
   case 64:
@@ -325,12 +358,13 @@
     case 24:			/* RGB image */
       TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
       break;
+    case 32:			/* RGB image + Alpha channel */
+      TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+      break;
     default:
       ERREXIT(cinfo, JERR_BMP_BADDEPTH);
       break;
     }
-    if (biPlanes != 1)
-      ERREXIT(cinfo, JERR_BMP_BADPLANES);
     if (biCompression != 0)
       ERREXIT(cinfo, JERR_BMP_COMPRESSED);
 
@@ -343,9 +377,14 @@
     break;
   default:
     ERREXIT(cinfo, JERR_BMP_BADHEADER);
-    break;
+    return;
   }
 
+  if (biWidth <= 0 || biHeight <= 0)
+    ERREXIT(cinfo, JERR_BMP_EMPTY);
+  if (biPlanes != 1)
+    ERREXIT(cinfo, JERR_BMP_BADPLANES);
+
   /* Compute distance to bitmap data --- will adjust for colormap below */
   bPad = bfOffBits - (headerSize + 14);
 
@@ -375,6 +414,8 @@
   /* Compute row width in file, including padding to 4-byte boundary */
   if (source->bits_per_pixel == 24)
     row_width = (JDIMENSION) (biWidth * 3);
+  else if (source->bits_per_pixel == 32)
+    row_width = (JDIMENSION) (biWidth * 4);
   else
     row_width = (JDIMENSION) biWidth;
   while ((row_width & 3) != 0) row_width++;
diff --git a/rdjpgcom.1 b/rdjpgcom.1
index 2bba04e..97611df 100644
--- a/rdjpgcom.1
+++ b/rdjpgcom.1
@@ -1,9 +1,12 @@
-.TH RDJPGCOM 1 "11 October 1997"
+.TH RDJPGCOM 1 "02 April 2009"
 .SH NAME
 rdjpgcom \- display text comments from a JPEG file
 .SH SYNOPSIS
 .B rdjpgcom
 [
+.B \-raw
+]
+[
 .B \-verbose
 ]
 [
@@ -25,6 +28,12 @@
 them as you like in one JPEG file.
 .SH OPTIONS
 .TP
+.B \-raw
+Normally
+.B rdjpgcom
+escapes non-printable characters in comments, for security reasons.
+This option avoids that.
+.PP
 .B \-verbose
 Causes
 .B rdjpgcom
diff --git a/rdjpgcom.c b/rdjpgcom.c
index ffe6fc6..3719154 100644
--- a/rdjpgcom.c
+++ b/rdjpgcom.c
@@ -2,6 +2,7 @@
  * rdjpgcom.c
  *
  * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -14,6 +15,9 @@
 #define JPEG_CJPEG_DJPEG	/* to get the command-line config symbols */
 #include "jinclude.h"		/* get auto-config symbols, <stdio.h> */
 
+#ifdef HAVE_LOCALE_H
+#include <locale.h>		/* Bill Allombert: use locale for isprint */
+#endif
 #include <ctype.h>		/* to declare isupper(), tolower() */
 #ifdef USE_SETMODE
 #include <fcntl.h>		/* to declare setmode()'s parameter macros */
@@ -218,12 +222,17 @@
  */
 
 static void
-process_COM (void)
+process_COM (int raw)
 {
   unsigned int length;
   int ch;
   int lastch = 0;
 
+  /* Bill Allombert: set locale properly for isprint */
+#ifdef HAVE_LOCALE_H
+  setlocale(LC_CTYPE, "");
+#endif
+
   /* Get the marker parameter length count */
   length = read_2_bytes();
   /* Length includes itself, so must be at least 2 */
@@ -233,12 +242,14 @@
 
   while (length > 0) {
     ch = read_1_byte();
+    if (raw) {
+      putc(ch, stdout);
     /* Emit the character in a readable form.
      * Nonprintables are converted to \nnn form,
      * while \ is converted to \\.
      * Newlines in CR, CR/LF, or LF form will be printed as one newline.
      */
-    if (ch == '\r') {
+    } else if (ch == '\r') {
       printf("\n");
     } else if (ch == '\n') {
       if (lastch != '\r')
@@ -254,6 +265,11 @@
     length--;
   }
   printf("\n");
+
+  /* Bill Allombert: revert to C locale */
+#ifdef HAVE_LOCALE_H
+  setlocale(LC_CTYPE, "C");
+#endif
 }
 
 
@@ -321,7 +337,7 @@
  */
 
 static int
-scan_JPEG_header (int verbose)
+scan_JPEG_header (int verbose, int raw)
 {
   int marker;
 
@@ -362,7 +378,7 @@
       return marker;
 
     case M_COM:
-      process_COM();
+      process_COM(raw);
       break;
 
     case M_APP12:
@@ -371,7 +387,7 @@
        */
       if (verbose) {
 	printf("APP12 contains:\n");
-	process_COM();
+	process_COM(raw);
       } else
 	skip_variable();
       break;
@@ -398,6 +414,7 @@
   fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
 
   fprintf(stderr, "Switches (names may be abbreviated):\n");
+  fprintf(stderr, "  -raw        Display non-printable characters in comments (unsafe)\n");
   fprintf(stderr, "  -verbose    Also display dimensions of JPEG image\n");
 
   exit(EXIT_FAILURE);
@@ -438,7 +455,7 @@
 {
   int argn;
   char * arg;
-  int verbose = 0;
+  int verbose = 0, raw = 0;
 
   /* On Mac, fetch a command line. */
 #ifdef USE_CCOMMAND
@@ -457,6 +474,8 @@
     arg++;			/* advance over '-' */
     if (keymatch(arg, "verbose", 1)) {
       verbose++;
+    } else if (keymatch(arg, "raw", 1)) {
+      raw = 1;
     } else
       usage();
   }
@@ -488,7 +507,7 @@
   }
 
   /* Scan the JPEG headers. */
-  (void) scan_JPEG_header(verbose);
+  (void) scan_JPEG_header(verbose, raw);
 
   /* All done. */
   exit(EXIT_SUCCESS);
diff --git a/rdppm.c b/rdppm.c
index 1df35c1..a757022 100644
--- a/rdppm.c
+++ b/rdppm.c
@@ -2,6 +2,7 @@
  * rdppm.c
  *
  * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -250,8 +251,8 @@
   bufferptr = source->iobuffer;
   for (col = cinfo->image_width; col > 0; col--) {
     register int temp;
-    temp  = UCH(*bufferptr++);
-    temp |= UCH(*bufferptr++) << 8;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
     *ptr++ = rescale[temp];
   }
   return 1;
@@ -274,14 +275,14 @@
   bufferptr = source->iobuffer;
   for (col = cinfo->image_width; col > 0; col--) {
     register int temp;
-    temp  = UCH(*bufferptr++);
-    temp |= UCH(*bufferptr++) << 8;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
     *ptr++ = rescale[temp];
-    temp  = UCH(*bufferptr++);
-    temp |= UCH(*bufferptr++) << 8;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
     *ptr++ = rescale[temp];
-    temp  = UCH(*bufferptr++);
-    temp |= UCH(*bufferptr++) << 8;
+    temp  = UCH(*bufferptr++) << 8;
+    temp |= UCH(*bufferptr++);
     *ptr++ = rescale[temp];
   }
   return 1;
diff --git a/rdswitch.c b/rdswitch.c
index 4f4bb4f..d406755 100644
--- a/rdswitch.c
+++ b/rdswitch.c
@@ -2,6 +2,7 @@
  * rdswitch.c
  *
  * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -9,6 +10,7 @@
  * command-line switches.  Switches processed here are:
  *	-qtables file		Read quantization tables from text file
  *	-scans file		Read scan script from text file
+ *	-quality N[,N,...]	Set quality ratings
  *	-qslots N[,N,...]	Set component quantization table selectors
  *	-sample HxV[,HxV,...]	Set component sampling factors
  */
@@ -69,9 +71,12 @@
 }
 
 
+#if JPEG_LIB_VERSION < 70
+static int q_scale_factor[NUM_QUANT_TBLS] = {100, 100, 100, 100};
+#endif
+
 GLOBAL(boolean)
-read_quant_tables (j_compress_ptr cinfo, char * filename,
-		   int scale_factor, boolean force_baseline)
+read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
 /* Read a set of quantization tables from the specified file.
  * The file is plain ASCII text: decimal numbers with whitespace between.
  * Comments preceded by '#' may be included in the file.
@@ -108,7 +113,13 @@
       }
       table[i] = (unsigned int) val;
     }
-    jpeg_add_quant_table(cinfo, tblno, table, scale_factor, force_baseline);
+#if JPEG_LIB_VERSION >= 70
+    jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
+			 force_baseline);
+#else
+    jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
+                         force_baseline);
+#endif
     tblno++;
   }
 
@@ -262,6 +273,84 @@
 #endif /* C_MULTISCAN_FILES_SUPPORTED */
 
 
+#if JPEG_LIB_VERSION < 70
+/* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+  16,  11,  10,  16,  24,  40,  51,  61,
+  12,  12,  14,  19,  26,  58,  60,  55,
+  14,  13,  16,  24,  40,  57,  69,  56,
+  14,  17,  22,  29,  51,  87,  80,  62,
+  18,  22,  37,  56,  68, 109, 103,  77,
+  24,  35,  55,  64,  81, 104, 113,  92,
+  49,  64,  78,  87, 103, 121, 120, 101,
+  72,  92,  95,  98, 112, 100, 103,  99
+};
+static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+  17,  18,  24,  47,  99,  99,  99,  99,
+  18,  21,  26,  66,  99,  99,  99,  99,
+  24,  26,  56,  99,  99,  99,  99,  99,
+  47,  66,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99,
+  99,  99,  99,  99,  99,  99,  99,  99
+};
+
+
+LOCAL(void)
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+{
+  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+		       q_scale_factor[0], force_baseline);
+  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+		       q_scale_factor[1], force_baseline);
+}
+#endif
+
+
+GLOBAL(boolean)
+set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
+/* Process a quality-ratings parameter string, of the form
+ *     N[,N,...]
+ * If there are more q-table slots than parameters, the last value is replicated.
+ */
+{
+  int val = 75;			/* default value */
+  int tblno;
+  char ch;
+
+  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+    if (*arg) {
+      ch = ',';			/* if not set by sscanf, will be ',' */
+      if (sscanf(arg, "%d%c", &val, &ch) < 1)
+	return FALSE;
+      if (ch != ',')		/* syntax check */
+	return FALSE;
+      /* Convert user 0-100 rating to percentage scaling */
+#if JPEG_LIB_VERSION >= 70
+      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+#else
+      q_scale_factor[tblno] = jpeg_quality_scaling(val);
+#endif
+      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+	;
+    } else {
+      /* reached end of parameter, set remaining factors to last value */
+#if JPEG_LIB_VERSION >= 70
+      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+#else
+      q_scale_factor[tblno] = jpeg_quality_scaling(val);
+#endif
+    }
+  }
+  jpeg_default_qtables(cinfo, force_baseline);
+  return TRUE;
+}
+
+
 GLOBAL(boolean)
 set_quant_slots (j_compress_ptr cinfo, char *arg)
 /* Process a quantization-table-selectors parameter string, of the form
diff --git a/release/Description.plist.tmpl b/release/Description.plist.in
similarity index 65%
rename from release/Description.plist.tmpl
rename to release/Description.plist.in
index 4c5875c..46a5bce 100644
--- a/release/Description.plist.tmpl
+++ b/release/Description.plist.in
@@ -3,10 +3,10 @@
 <plist version="1.0">
 <dict>
 	<key>IFPkgDescriptionDescription</key>
-	<string>A SIMD-accelerated JPEG codec which provides both the libjpeg and TurboJPEG APIs</string>
+	<string>A SIMD-accelerated JPEG codec that provides both the libjpeg and TurboJPEG APIs</string>
 	<key>IFPkgDescriptionTitle</key>
-	<string>{__APPNAME}</string>
+	<string>@PACKAGE_NAME@</string>
 	<key>IFPkgDescriptionVersion</key>
-	<string>{__VERSION}</string>
+	<string>@VERSION@</string>
 </dict>
 </plist>
diff --git a/release/Info.plist.tmpl b/release/Info.plist.in
similarity index 90%
rename from release/Info.plist.tmpl
rename to release/Info.plist.in
index a33daae..0575079 100755
--- a/release/Info.plist.tmpl
+++ b/release/Info.plist.in
@@ -3,15 +3,15 @@
 <plist version="1.0">
 <dict>
 	<key>CFBundleGetInfoString</key>
-	<string>{__VERSION}, The libjpeg-turbo Project</string>
+	<string>@VERSION@, The libjpeg-turbo Project</string>
 	<key>CFBundleIdentifier</key>
 	<string>com.libjpeg-turbo.libjpeg-turbo</string>
 	<key>CFBundleShortVersionString</key>
-	<string>{__VERSION}</string>
+	<string>@VERSION@</string>
 	<key>IFMajorVersion</key>
 	<integer>1</integer>
 	<key>IFMinorVersion</key>
-	<integer>{__BUILD}</integer>
+	<integer>@BUILD@</integer>
 	<key>IFPkgFlagAllowBackRev</key>
 	<false/>
 	<key>IFPkgFlagAuthorizationAction</key>
diff --git a/release/ReadMe.rtf b/release/ReadMe.rtf
index b7f156e..06c94ab 100644
--- a/release/ReadMe.rtf
+++ b/release/ReadMe.rtf
@@ -1,11 +1,13 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf250
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
 {\fonttbl\f0\fswiss\fcharset0 Helvetica;}
 {\colortbl;\red255\green255\blue255;}
 \margl1440\margr1440\vieww15200\viewh9600\viewkind0
 \deftab720
 \pard\pardeftab720\ql\qnatural
 
-\f0\fs24 \cf0 libjpeg-turbo is a high-speed version of libjpeg for x86 and x86-64 processors which uses SIMD instructions (MMX, SSE2, etc.) to accelerate baseline JPEG compression and decompression.  libjpeg-turbo is generally 2-4x as fast as the unmodified version of libjpeg, all else being equal.  libjpeg-turbo also includes a wrapper library for the TurboJPEG API used by VirtualGL and TurboVNC.\
+\f0\fs24 \cf0 libjpeg-turbo is a derivative of libjpeg 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 the unmodified version of libjpeg, all else being equal.\
 \
-libjpeg-turbo was originally based on libjpeg/SIMD by Miyasaka Masaru, but the TigerVNC and VirtualGL projects made numerous enhancements to the codec, including improved support for Mac OS X, 64-bit support, support for 32-bit and big endian pixel formats, accelerated Huffman encoding/decoding, and various bug fixes.  The goal was to produce a fully open source codec that could replace the partially closed source TurboJPEG/IPP codec used by VirtualGL and TurboVNC.  libjpeg-turbo generally performs in the range of 80-120% of TurboJPEG/IPP.  It is faster in some areas but slower in others.\
+libjpeg-turbo was originally based on libjpeg/SIMD by Miyasaka Masaru, but the TigerVNC and VirtualGL projects made numerous enhancements to the codec in 2009, including improved support for Mac OS X, 64-bit support, support for 32-bit and big-endian pixel formats (RGBX, XBGR, etc.), accelerated Huffman encoding/decoding, and various bug fixes.  The goal was to produce a fully open-source codec that could replace the partially closed-source TurboJPEG/IPP codec used by VirtualGL and TurboVNC.  libjpeg-turbo generally achieves 80-120% of the performance of TurboJPEG/IPP.  It is faster in some areas but slower in others.\
+\
+In early 2010, libjpeg-turbo spun off into its own independent project, with the goal of making high-speed JPEG compression/decompression technology available to a broader range of users and developers.\
 }
\ No newline at end of file
diff --git a/release/deb-control.tmpl b/release/deb-control.tmpl
index 0a3f11f..9cf7c46 100644
--- a/release/deb-control.tmpl
+++ b/release/deb-control.tmpl
@@ -5,19 +5,22 @@
 Architecture: {__ARCH}
 Essential: no
 Maintainer: The libjpeg-turbo Project [http://www.libjpeg-turbo.org]
-Description: A SIMD-accelerated JPEG codec which provides both the libjpeg and TurboJPEG APIs
- libjpeg-turbo is a high-speed version of libjpeg for x86 and x86-64 processors
- which uses SIMD instructions (MMX, SSE2, etc.) to accelerate baseline JPEG
- compression and decompression.  libjpeg-turbo is generally 2-4x as fast
- as the unmodified version of libjpeg, all else being equal.  libjpeg-turbo
- also includes a wrapper library for the TurboJPEG API used by VirtualGL and
- TurboVNC.
+Description: A SIMD-accelerated JPEG codec that provides both the libjpeg and TurboJPEG APIs
+ libjpeg-turbo is a derivative of libjpeg 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 the unmodified version of libjpeg, all else being equal.
  .
  libjpeg-turbo was originally based on libjpeg/SIMD by Miyasaka Masaru, but
- the TigerVNC and VirtualGL projects made numerous enhancements to the codec,
- including improved support for Mac OS X, 64-bit support, support for 32-bit
- and big endian pixel formats, accelerated Huffman encoding/decoding, and
- various bug fixes.  The goal was to produce a fully open source codec that
- could replace the partially closed source TurboJPEG/IPP codec used by
- VirtualGL and TurboVNC.  libjpeg-turbo generally performs in the range of
- 80-120% of TurboJPEG/IPP.  It is faster in some areas but slower in others.
+ the TigerVNC and VirtualGL projects made numerous enhancements to the codec
+ in 2009, including improved support for Mac OS X, 64-bit support, support
+ for 32-bit and big-endian pixel formats (RGBX, XBGR, etc.), accelerated
+ Huffman encoding/decoding, and various bug fixes.  The goal was to produce a
+ fully open-source codec that could replace the partially closed-source
+ TurboJPEG/IPP codec used by VirtualGL and TurboVNC.  libjpeg-turbo generally
+ achieves 80-120% of the performance of TurboJPEG/IPP.  It is faster in some
+ areas but slower in others.
+ .
+ In early 2010, libjpeg-turbo spun off into its own independent project, with
+ the goal of making high-speed JPEG compression/decompression technology
+ available to a broader range of users and developers.
diff --git a/release/libjpeg-turbo.nsi b/release/libjpeg-turbo.nsi
deleted file mode 100644
index e944466..0000000
--- a/release/libjpeg-turbo.nsi
+++ /dev/null
@@ -1,126 +0,0 @@
-!include x64.nsh
-Name "libjpeg-turbo SDK for ${PLATFORM}"
-OutFile ${WBLDDIR}\${APPNAME}.exe
-InstallDir c:\${APPNAME}
-
-SetCompressor bzip2
-
-Page directory
-Page instfiles
-
-UninstPage uninstConfirm
-UninstPage instfiles
-
-Section "libjpeg-turbo SDK for ${PLATFORM} (required)"
-!ifdef WIN64
-	${If} ${RunningX64}
-	${DisableX64FSRedirection}
-	${Endif}
-!endif
-	SectionIn RO
-!ifdef GCC
-	IfFileExists $SYSDIR/libturbojpeg.dll exists 0
-!else
-	IfFileExists $SYSDIR/turbojpeg.dll exists 0
-!endif
-	goto notexists
-	exists:
-!ifdef GCC
-	MessageBox MB_OK "An existing version of the libjpeg-turbo SDK for ${PLATFORM} is already installed.  Please uninstall it first."
-!else
-	MessageBox MB_OK "An existing version of the libjpeg-turbo SDK for ${PLATFORM} or the TurboJPEG SDK is already installed.  Please uninstall it first."
-!endif
-	quit
-
-	notexists:
-	SetOutPath $SYSDIR
-!ifdef GCC
-	File "${WLIBDIR}\libturbojpeg.dll"
-!else
-	File "${WLIBDIR}\turbojpeg.dll"
-!endif
-	SetOutPath $INSTDIR\bin
-!ifdef GCC
-	File "/oname=libjpeg-62.dll" "${WLIBDIR}\libjpeg-*.dll" 
-!else
-	File "${WLIBDIR}\jpeg62.dll"
-!endif
-	SetOutPath $INSTDIR\lib
-!ifdef GCC
-	File "${WLIBDIR}\libturbojpeg.dll.a"
-	File "${WLIBDIR}\libturbojpeg.a"
-	File "${WLIBDIR}\libjpeg.dll.a"
-	File "${WLIBDIR}\libjpeg.a"
-!else
-	File "${WLIBDIR}\turbojpeg.lib"
-	File "${WLIBDIR}\turbojpeg-static.lib"
-	File "${WLIBDIR}\jpeg.lib"
-	File "${WLIBDIR}\jpeg-static.lib"
-!endif
-	SetOutPath $INSTDIR\include
-	File "${WHDRDIR}\jconfig.h"
-	File "${WSRCDIR}\jerror.h"
-	File "${WSRCDIR}\jmorecfg.h"
-	File "${WSRCDIR}\jpeglib.h"
-	File "${WSRCDIR}\turbojpeg.h"
-	SetOutPath $INSTDIR
-	File "${WSRCDIR}\README"
-	File "${WSRCDIR}\README-turbo.txt"
-	File "${WSRCDIR}\libjpeg.doc"
-	File "${WSRCDIR}\LGPL.txt"
-	File "${WSRCDIR}\LICENSE.txt"
-
-	WriteRegStr HKLM "SOFTWARE\${APPNAME} ${VERSION}" "Install_Dir" "$INSTDIR"
-
-	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME} ${VERSION}" "DisplayName" "libjpeg-turbo SDK v${VERSION} for ${PLATFORM}"
-	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME} ${VERSION}" "UninstallString" '"$INSTDIR\uninstall_${VERSION}.exe"'
-	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME} ${VERSION}" "NoModify" 1
-	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME} ${VERSION}" "NoRepair" 1
-	WriteUninstaller "uninstall_${VERSION}.exe"
-SectionEnd
-
-Section "Uninstall"
-!ifdef WIN64
-	${If} ${RunningX64}
-	${DisableX64FSRedirection}
-	${Endif}
-!endif
-
-	SetShellVarContext all
-
-	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME} ${VERSION}"
-	DeleteRegKey HKLM "SOFTWARE\${APPNAME} ${VERSION}"
-
-!ifdef GCC
-	Delete $INSTDIR\bin\libjpeg-62.dll
-	Delete $SYSDIR\libturbojpeg.dll
-	Delete $INSTDIR\lib\libturbojpeg.dll.a"
-	Delete $INSTDIR\lib\libturbojpeg.a"
-	Delete $INSTDIR\lib\libjpeg.dll.a"
-	Delete $INSTDIR\lib\libjpeg.a"
-!else
-	Delete $INSTDIR\bin\jpeg62.dll
-	Delete $SYSDIR\turbojpeg.dll
-	Delete $INSTDIR\lib\jpeg.lib
-	Delete $INSTDIR\lib\jpeg-static.lib
-	Delete $INSTDIR\lib\turbojpeg.lib
-	Delete $INSTDIR\lib\turbojpeg-static.lib
-!endif
-	Delete $INSTDIR\include\jconfig.h"
-	Delete $INSTDIR\include\jerror.h"
-	Delete $INSTDIR\include\jmorecfg.h"
-	Delete $INSTDIR\include\jpeglib.h"
-	Delete $INSTDIR\include\turbojpeg.h"
-	Delete $INSTDIR\uninstall_${VERSION}.exe
-	Delete $INSTDIR\README
-	Delete $INSTDIR\README-turbo.txt
-	Delete $INSTDIR\libjpeg.doc
-	Delete $INSTDIR\LGPL.txt
-	Delete $INSTDIR\LICENSE.txt
-
-	RMDir "$INSTDIR\include"
-	RMDir "$INSTDIR\lib"
-	RMDir "$INSTDIR\bin"
-	RMDir "$INSTDIR"
-
-SectionEnd
diff --git a/release/libjpeg-turbo.nsi.in b/release/libjpeg-turbo.nsi.in
new file mode 100755
index 0000000..6eb4bae
--- /dev/null
+++ b/release/libjpeg-turbo.nsi.in
@@ -0,0 +1,141 @@
+!include x64.nsh
+Name "@CMAKE_PROJECT_NAME@ SDK for @INST_PLATFORM@"
+OutFile "@CMAKE_BINARY_DIR@\${BUILDDIR}@INST_NAME@.exe"
+InstallDir c:\@INST_DIR@
+
+SetCompressor bzip2
+
+Page directory
+Page instfiles
+
+UninstPage uninstConfirm
+UninstPage instfiles
+
+Section "@CMAKE_PROJECT_NAME@ SDK for @INST_PLATFORM@ (required)"
+!ifdef WIN64
+	${If} ${RunningX64}
+	${DisableX64FSRedirection}
+	${Endif}
+!endif
+	SectionIn RO
+!ifdef GCC
+	IfFileExists $SYSDIR/libturbojpeg.dll exists 0
+!else
+	IfFileExists $SYSDIR/turbojpeg.dll exists 0
+!endif
+	goto notexists
+	exists:
+!ifdef GCC
+	MessageBox MB_OK "An existing version of the @CMAKE_PROJECT_NAME@ SDK for @INST_PLATFORM@ is already installed.  Please uninstall it first."
+!else
+	MessageBox MB_OK "An existing version of the @CMAKE_PROJECT_NAME@ SDK for @INST_PLATFORM@ or the TurboJPEG SDK is already installed.  Please uninstall it first."
+!endif
+	quit
+
+	notexists:
+	SetOutPath $SYSDIR
+!ifdef GCC
+	File "@CMAKE_BINARY_DIR@\libturbojpeg.dll"
+!else
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}turbojpeg.dll"
+!endif
+	SetOutPath $INSTDIR\bin
+!ifdef GCC
+	File "/oname=libjpeg-@DLL_VERSION@.dll" "@CMAKE_BINARY_DIR@\sharedlib\libjpeg-*.dll" 
+!else
+	File "@CMAKE_BINARY_DIR@\sharedlib\${BUILDDIR}jpeg@DLL_VERSION@.dll"
+!endif
+	File "@CMAKE_BINARY_DIR@\sharedlib\${BUILDDIR}cjpeg.exe"
+	File "@CMAKE_BINARY_DIR@\sharedlib\${BUILDDIR}djpeg.exe"
+	File "@CMAKE_BINARY_DIR@\sharedlib\${BUILDDIR}jpegtran.exe"
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}jpgtest.exe"
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}rdjpgcom.exe"
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}wrjpgcom.exe"
+	SetOutPath $INSTDIR\lib
+!ifdef GCC
+	File "@CMAKE_BINARY_DIR@\libturbojpeg.dll.a"
+	File "@CMAKE_BINARY_DIR@\libturbojpeg.a"
+	File "@CMAKE_BINARY_DIR@\sharedlib\libjpeg.dll.a"
+	File "@CMAKE_BINARY_DIR@\libjpeg.a"
+!else
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}turbojpeg.lib"
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}turbojpeg-static.lib"
+	File "@CMAKE_BINARY_DIR@\sharedlib\${BUILDDIR}jpeg.lib"
+	File "@CMAKE_BINARY_DIR@\${BUILDDIR}jpeg-static.lib"
+!endif
+	SetOutPath $INSTDIR\include
+	File "@CMAKE_BINARY_DIR@\jconfig.h"
+	File "@CMAKE_SOURCE_DIR@\jerror.h"
+	File "@CMAKE_SOURCE_DIR@\jmorecfg.h"
+	File "@CMAKE_SOURCE_DIR@\jpeglib.h"
+	File "@CMAKE_SOURCE_DIR@\turbojpeg.h"
+	SetOutPath $INSTDIR\doc
+	File "@CMAKE_SOURCE_DIR@\README"
+	File "@CMAKE_SOURCE_DIR@\README-turbo.txt"
+	File "@CMAKE_SOURCE_DIR@\libjpeg.txt"
+	File "@CMAKE_SOURCE_DIR@\LGPL.txt"
+	File "@CMAKE_SOURCE_DIR@\LICENSE.txt"
+	File "@CMAKE_SOURCE_DIR@\usage.txt"
+
+	WriteRegStr HKLM "SOFTWARE\@INST_DIR@ @VERSION@" "Install_Dir" "$INSTDIR"
+
+	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@INST_DIR@ @VERSION@" "DisplayName" "@CMAKE_PROJECT_NAME@ SDK v@VERSION@ for @INST_PLATFORM@"
+	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@INST_DIR@ @VERSION@" "UninstallString" '"$INSTDIR\uninstall_@VERSION@.exe"'
+	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@INST_DIR@ @VERSION@" "NoModify" 1
+	WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@INST_DIR@ @VERSION@" "NoRepair" 1
+	WriteUninstaller "uninstall_@VERSION@.exe"
+SectionEnd
+
+Section "Uninstall"
+!ifdef WIN64
+	${If} ${RunningX64}
+	${DisableX64FSRedirection}
+	${Endif}
+!endif
+
+	SetShellVarContext all
+
+	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@INST_DIR@ @VERSION@"
+	DeleteRegKey HKLM "SOFTWARE\@INST_DIR@ @VERSION@"
+
+!ifdef GCC
+	Delete $INSTDIR\bin\libjpeg-@DLL_VERSION@.dll
+	Delete $SYSDIR\libturbojpeg.dll
+	Delete $INSTDIR\lib\libturbojpeg.dll.a"
+	Delete $INSTDIR\lib\libturbojpeg.a"
+	Delete $INSTDIR\lib\libjpeg.dll.a"
+	Delete $INSTDIR\lib\libjpeg.a"
+!else
+	Delete $INSTDIR\bin\jpeg@DLL_VERSION@.dll
+	Delete $SYSDIR\turbojpeg.dll
+	Delete $INSTDIR\lib\jpeg.lib
+	Delete $INSTDIR\lib\jpeg-static.lib
+	Delete $INSTDIR\lib\turbojpeg.lib
+	Delete $INSTDIR\lib\turbojpeg-static.lib
+!endif
+	Delete $INSTDIR\bin\cjpeg.exe
+	Delete $INSTDIR\bin\djpeg.exe
+	Delete $INSTDIR\bin\jpegtran.exe
+	Delete $INSTDIR\bin\jpgtest.exe
+	Delete $INSTDIR\bin\rdjpgcom.exe
+	Delete $INSTDIR\bin\wrjpgcom.exe
+	Delete $INSTDIR\include\jconfig.h"
+	Delete $INSTDIR\include\jerror.h"
+	Delete $INSTDIR\include\jmorecfg.h"
+	Delete $INSTDIR\include\jpeglib.h"
+	Delete $INSTDIR\include\turbojpeg.h"
+	Delete $INSTDIR\uninstall_@VERSION@.exe
+	Delete $INSTDIR\doc\README
+	Delete $INSTDIR\doc\README-turbo.txt
+	Delete $INSTDIR\doc\libjpeg.txt
+	Delete $INSTDIR\doc\LGPL.txt
+	Delete $INSTDIR\doc\LICENSE.txt
+	Delete $INSTDIR\doc\usage.txt
+
+	RMDir "$INSTDIR\include"
+	RMDir "$INSTDIR\lib"
+	RMDir "$INSTDIR\doc"
+	RMDir "$INSTDIR\bin"
+	RMDir "$INSTDIR"
+
+SectionEnd
diff --git a/release/libjpeg-turbo.spec b/release/libjpeg-turbo.spec.in
similarity index 61%
rename from release/libjpeg-turbo.spec
rename to release/libjpeg-turbo.spec.in
index 0c205ba..fdb3e98 100644
--- a/release/libjpeg-turbo.spec
+++ b/release/libjpeg-turbo.spec.in
@@ -4,14 +4,14 @@
 %define __lib lib
 %endif
 
-Summary: A SIMD-accelerated JPEG codec which provides both the libjpeg and TurboJPEG APIs
-Name: %{_name}
-Version: %{_version}
+Summary: A SIMD-accelerated JPEG codec that provides both the libjpeg and TurboJPEG APIs
+Name: @PACKAGE_NAME@
+Version: @VERSION@
 Vendor: The libjpeg-turbo Project
 URL: http://www.libjpeg-turbo.org
 Group: System Environment/Libraries
 #-->Source0: http://prdownloads.sourceforge.net/libjpeg-turbo/libjpeg-turbo-%{version}.tar.gz
-Release: %{_build}
+Release: @BUILD@
 License: wxWindows Library License, v3.1
 BuildRoot: %{_blddir}/%{name}-buildroot-%{version}-%{release}
 Prereq: /sbin/ldconfig
@@ -19,27 +19,30 @@
 Obsoletes: turbojpeg
 
 %description
-libjpeg-turbo is a high-speed version of libjpeg for x86 and x86-64 processors
-which uses SIMD instructions (MMX, SSE2, etc.) to accelerate baseline JPEG
-compression and decompression.  libjpeg-turbo is generally 2-4x as fast
-as the unmodified version of libjpeg, all else being equal.  libjpeg-turbo also
-includes a wrapper library for the TurboJPEG API used by VirtualGL and
-TurboVNC.
+libjpeg-turbo is a derivative of libjpeg 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 the unmodified version of libjpeg, all else being equal.
 
 libjpeg-turbo was originally based on libjpeg/SIMD by Miyasaka Masaru, but
-the TigerVNC and VirtualGL projects made numerous enhancements to the codec,
-including improved support for Mac OS X, 64-bit support, support for 32-bit
-and big endian pixel formats, accelerated Huffman encoding/decoding, and
-various bug fixes.  The goal was to produce a fully open source codec that
-could replace the partially closed source TurboJPEG/IPP codec used by VirtualGL
-and TurboVNC.  libjpeg-turbo generally performs in the range of 80-120% of
-TurboJPEG/IPP.  It is faster in some areas but slower in others.
+the TigerVNC and VirtualGL projects made numerous enhancements to the codec in
+2009, including improved support for Mac OS X, 64-bit support, support for
+32-bit and big-endian pixel formats (RGBX, XBGR, etc.), accelerated Huffman
+encoding/decoding, and various bug fixes.  The goal was to produce a fully
+open-source codec that could replace the partially closed-source TurboJPEG/IPP
+codec used by VirtualGL and TurboVNC.  libjpeg-turbo generally achieves 80-120%
+of the performance of TurboJPEG/IPP.  It is faster in some areas but slower in
+others.
+
+In early 2010, libjpeg-turbo spun off into its own independent project, with
+the goal of making high-speed JPEG compression/decompression technology
+available to a broader range of users and developers.
 
 #-->%prep
 #-->%setup -q
 
 #-->%build
-#-->configure libdir=/opt/%{name}/%{__lib} mandir=/opt/%{name}/man --with-pic
+#-->./configure libdir=/opt/%{name}/%{__lib} mandir=/opt/%{name}/man JPEG_LIB_VERSION=@JPEG_LIB_VERSION@ SO_MAJOR_VERSION=@SO_MAJOR_VERSION@ SO_MINOR_VERSION=@SO_MINOR_VERSION@ --with-pic
 #-->make DESTDIR=$RPM_BUILD_ROOT libdir=/opt/%{name}/%{__lib} mandir=/opt/%{name}/man
 
 %install
@@ -55,10 +58,6 @@
 mv $RPM_BUILD_ROOT/opt/%{name}/include/turbojpeg.h $RPM_BUILD_ROOT/usr/include
 ln -fs /usr/include/turbojpeg.h $RPM_BUILD_ROOT/opt/%{name}/include/
 ln -fs /usr/%{__lib}/libturbojpeg.a $RPM_BUILD_ROOT/opt/%{name}/%{__lib}/
-%ifarch x86_64
-%else
-ln -fs %{__lib} $RPM_BUILD_ROOT/opt/%{name}/lib32
-%endif
 
 %post -p /sbin/ldconfig
 
@@ -69,12 +68,13 @@
 
 %files
 %defattr(-,root,root)
-%doc %{_srcdir}/README-turbo.txt %{_srcdir}/README %{_srcdir}/libjpeg.doc %{_srcdir}/usage.doc %{_srcdir}/LICENSE.txt %{_srcdir}/LGPL.txt
+%doc %{_srcdir}/README-turbo.txt %{_srcdir}/README %{_srcdir}/libjpeg.txt %{_srcdir}/usage.txt %{_srcdir}/LICENSE.txt %{_srcdir}/LGPL.txt
 %dir /opt/%{name}
 %dir /opt/%{name}/bin
 /opt/%{name}/bin/cjpeg
 /opt/%{name}/bin/djpeg
 /opt/%{name}/bin/jpegtran
+/opt/%{name}/bin/jpgtest
 /opt/%{name}/bin/rdjpgcom
 /opt/%{name}/bin/wrjpgcom
 %dir /opt/%{name}/%{__lib}
@@ -82,8 +82,8 @@
 %else
 /opt/%{name}/lib32
 %endif
-/opt/%{name}/%{__lib}/libjpeg.so.62.0.0
-/opt/%{name}/%{__lib}/libjpeg.so.62
+/opt/%{name}/%{__lib}/libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@
+/opt/%{name}/%{__lib}/libjpeg.so.@SO_MAJOR_VERSION@
 /opt/%{name}/%{__lib}/libjpeg.so
 /opt/%{name}/%{__lib}/libjpeg.a
 /opt/%{name}/%{__lib}/libturbojpeg.a
diff --git a/release/makecygwinpkg b/release/makecygwinpkg.in
similarity index 76%
rename from release/makecygwinpkg
rename to release/makecygwinpkg.in
index 981cd9e..51d5852 100755
--- a/release/makecygwinpkg
+++ b/release/makecygwinpkg.in
@@ -15,16 +15,9 @@
 	fi
 }
 
-usage()
-{
-	echo "$0 <package name> <version> <source dir.>"
-	exit 1
-}
-
-if [ $# -lt 3 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-SRCDIR=$3
+PACKAGE_NAME=@PACKAGE_NAME@
+VERSION=@VERSION@
+SRCDIR=@abs_top_srcdir@
 
 umask 022
 rm -f $PACKAGE_NAME-$VERSION-cygwin.tar.bz2
@@ -36,8 +29,8 @@
 mkdir -p $DOCDIR
 install -m 644 $SRCDIR/README-turbo.txt $DOCDIR
 install -m 644 $SRCDIR/README $DOCDIR
-install -m 644 $SRCDIR/libjpeg.doc $DOCDIR
-install -m 644 $SRCDIR/usage.doc $DOCDIR
+install -m 644 $SRCDIR/libjpeg.txt $DOCDIR
+install -m 644 $SRCDIR/usage.txt $DOCDIR
 install -m 644 $SRCDIR/LICENSE.txt $DOCDIR
 install -m 644 $SRCDIR/LGPL.txt $DOCDIR
 ln -fs lib $TMPDIR/pkg/opt/$PACKAGE_NAME/lib32
diff --git a/release/makedpkg b/release/makedpkg.in
similarity index 83%
rename from release/makedpkg
rename to release/makedpkg.in
index ec4e195..aaaeacb 100644
--- a/release/makedpkg
+++ b/release/makedpkg.in
@@ -15,12 +15,6 @@
 	fi
 }
 
-usage()
-{
-	echo "$0 <package name> <version> <build> <DEB architecture> <source dir.>"
-	exit 1
-}
-
 makedeb()
 {
 	SUPPLEMENT=$1
@@ -35,7 +29,7 @@
 	fi
 
 	umask 022
-	rm -f $PACKAGE_NAME\_$DEBARCH.deb
+	rm -f $PACKAGE_NAME\_$VERSION\_$DEBARCH.deb
 	TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
 	mkdir $TMPDIR/DEBIAN
 	(cat $SRCDIR/release/deb-control.tmpl | sed s/{__PKGNAME}/$PACKAGE_NAME/g \
@@ -73,20 +67,19 @@
 		install -m 644 $SRCDIR/LGPL.txt $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
 		install -m 644 $SRCDIR/README-turbo.txt $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
 		install -m 644 $SRCDIR/README $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
-		install -m 644 $SRCDIR/libjpeg.doc $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
-		install -m 644 $SRCDIR/usage.doc $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
+		install -m 644 $SRCDIR/libjpeg.txt $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
+		install -m 644 $SRCDIR/usage.txt $TMPDIR/usr/share/doc/$DIRNAME-$VERSION
 	fi
 
 	sudo chown -Rh root:root $TMPDIR/*
-	dpkg -b $TMPDIR $PACKAGE_NAME\_$DEBARCH.deb
+	dpkg -b $TMPDIR $PACKAGE_NAME\_$VERSION\_$DEBARCH.deb
 }
 
-if [ $# -lt 5 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-BUILD=$3
-DEBARCH=$4
-SRCDIR=$5
+PACKAGE_NAME=@PACKAGE_NAME@
+VERSION=@VERSION@
+BUILD=@BUILD@
+DEBARCH=@DEBARCH@
+SRCDIR=@abs_top_srcdir@
 
 makedeb 0
 if [ "$DEBARCH" = "i386" ]; then makedeb 1; fi
diff --git a/release/makemacpkg b/release/makemacpkg
deleted file mode 100644
index 6307e88..0000000
--- a/release/makemacpkg
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/bin/sh
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-TMPDIR=
-
-onexit()
-{
-	if [ ! "$TMPDIR" = "" ]; then
-		sudo rm -rf $TMPDIR
-	fi
-}
-
-usage()
-{
-	echo "$0 <package name> <version> <build> <source dir.> [universal]"
-	exit 1
-}
-
-UNIVERSAL=0
-
-if [ $# -lt 4 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-BUILD=$3
-SRCDIR=$4
-if [ $# -gt 4 ]; then
-	if [ "$5" = "universal" ]; then UNIVERSAL=1; fi
-fi
-PACKAGEMAKER=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
-
-if [ -f $PACKAGE_NAME.dmg ]; then
-	rm -f $PACKAGE_NAME.dmg
-fi
-
-umask 022
-TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
-PKGROOT=$TMPDIR/pkg/Package_Root
-mkdir -p $PKGROOT
-mkdir -p $PKGROOT/opt/$PACKAGE_NAME/bin
-make install DESTDIR=$PKGROOT mandir=/opt/$PACKAGE_NAME/man
-rm -f $PKGROOT/opt/$PACKAGE_NAME/lib/*.la
-mkdir -p $PKGROOT/usr/lib
-mv $PKGROOT/opt/$PACKAGE_NAME/lib/libturbojpeg.* $PKGROOT/usr/lib
-mkdir -p $PKGROOT/usr/include
-mv $PKGROOT/opt/$PACKAGE_NAME/include/turbojpeg.h $PKGROOT/usr/include
-
-if [ $UNIVERSAL = 1 ]; then
-	if [ ! -d $SRCDIR/osxx86 ]; then
-		mkdir -p $SRCDIR/osxx86
-	fi
-	mkdir -p $TMPDIR/dist.x86
-	pushd $SRCDIR/osxx86
-	sh $SRCDIR/configure --with-pic \
-		CFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -O3 -m32' \
-		CXXFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -O3 -m32' \
-		LDFLAGS='-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -m32'
-	make install DESTDIR=$TMPDIR/dist.x86
-	popd
-	if [ ! -h $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib -a \
-		! -h $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib ]; then
-		lipo -create \
-			-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib \
-			-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib \
-			-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib
-	elif [ ! -h $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.62.0.0.dylib -a \
-		! -h $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.0.0.dylib ]; then
-		lipo -create \
-			-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.62.0.0.dylib \
-			-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.0.0.dylib \
-			-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.0.0.dylib
-	fi
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.a \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.a \
-		-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.a
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libturbojpeg.dylib \
-		-arch x86_64 $PKGROOT/usr/lib/libturbojpeg.dylib \
-		-output $PKGROOT/usr/lib/libturbojpeg.dylib
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libturbojpeg.a \
-		-arch x86_64 $PKGROOT/usr/lib/libturbojpeg.a \
-		-output $PKGROOT/usr/lib/libturbojpeg.a
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/cjpeg \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/cjpeg \
-		-output $PKGROOT/opt/$PACKAGE_NAME/bin/cjpeg
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/djpeg \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/djpeg \
-		-output $PKGROOT/opt/$PACKAGE_NAME/bin/djpeg
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/jpegtran \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/jpegtran \
-		-output $PKGROOT/opt/$PACKAGE_NAME/bin/jpegtran
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/rdjpgcom \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/rdjpgcom \
-		-output $PKGROOT/opt/$PACKAGE_NAME/bin/rdjpgcom
-	lipo -create \
-		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/wrjpgcom \
-		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/wrjpgcom \
-		-output $PKGROOT/opt/$PACKAGE_NAME/bin/wrjpgcom
-
-fi
-
-install_name_tool -id /opt/$PACKAGE_NAME/lib/libjpeg.62.dylib $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.62.dylib
-install_name_tool -id libturbojpeg.dylib $PKGROOT/usr/lib/libturbojpeg.dylib
-
-ln -fs /usr/include/turbojpeg.h $PKGROOT/opt/$PACKAGE_NAME/include/
-ln -fs /usr/lib/libturbojpeg.a $PKGROOT/opt/$PACKAGE_NAME/lib/
-ln -fs lib $PKGROOT/opt/$PACKAGE_NAME/lib32
-ln -fs lib $PKGROOT/opt/$PACKAGE_NAME/lib64
-
-mkdir -p $PKGROOT/Library/Documentation/$PACKAGE_NAME
-chmod 1775 $PKGROOT/Library
-chmod 775 $PKGROOT/Library/Documentation 
-mkdir -p $TMPDIR/pkg/Resources 
-
-(cat $SRCDIR/release/Description.plist.tmpl | sed s/{__VERSION}/$VERSION/g \
-	| sed s/{__APPNAME}/$PACKAGE_NAME/g \
-	> $TMPDIR/pkg/Description.plist) 
-(cat $SRCDIR/release/Info.plist.tmpl | sed s/{__VERSION}/$VERSION/g	\
-	| sed s/{__BUILD}/$BUILD/g > $TMPDIR/pkg/Info.plist) 
-(cat $SRCDIR/release/uninstall.sh.tmpl \
-	| sed s/{__APPNAME}/$PACKAGE_NAME/g \
-	> $PKGROOT/opt/$PACKAGE_NAME/bin/uninstall) 
-chmod 755 $PKGROOT/opt/$PACKAGE_NAME/bin/uninstall
-
-install -m 644 $SRCDIR/LICENSE.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/LICENSE.txt 
-install -m 644 $SRCDIR/LGPL.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/LGPL.txt 
-install -m 644 $SRCDIR/README-turbo.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/README-turbo.txt 
-install -m 644 $SRCDIR/README $PKGROOT/Library/Documentation/$PACKAGE_NAME/README 
-install -m 644 $SRCDIR/libjpeg.doc $PKGROOT/Library/Documentation/$PACKAGE_NAME/libjpeg.doc 
-install -m 644 $SRCDIR/usage.doc $PKGROOT/Library/Documentation/$PACKAGE_NAME/usage.doc 
-
-sudo chown -R root:admin $PKGROOT 
-sudo chown -R root:0 $PKGROOT/usr 
-cp $SRCDIR/release/License.rtf $SRCDIR/release/Welcome.rtf $SRCDIR/release/ReadMe.rtf $TMPDIR/pkg/Resources/ 
-
-mkdir $TMPDIR/dmg
-$PACKAGEMAKER -build -v -p $TMPDIR/dmg/$PACKAGE_NAME.pkg \
-	-f $PKGROOT -r $TMPDIR/pkg/Resources \
-	-i $TMPDIR/pkg/Info.plist -d $TMPDIR/pkg/Description.plist 
-install -m 644 $SRCDIR/release/uninstall.applescript $TMPDIR 
-sudo osacompile -t APPL -o "$TMPDIR/dmg/Uninstall $PACKAGE_NAME.app" $TMPDIR/uninstall.applescript 
-sudo chown -R $USER "$TMPDIR/dmg/Uninstall $PACKAGE_NAME.app" 
-hdiutil create -fs HFS+ -volname $PACKAGE_NAME-$VERSION \
-	-srcfolder "$TMPDIR/dmg" \
-	$TMPDIR/$PACKAGE_NAME.dmg 
-cp $TMPDIR/$PACKAGE_NAME.dmg . 
-
-exit
diff --git a/release/makemacpkg.in b/release/makemacpkg.in
new file mode 100644
index 0000000..4fee6c1
--- /dev/null
+++ b/release/makemacpkg.in
@@ -0,0 +1,163 @@
+#!/bin/sh
+
+set -u
+set -e
+trap onexit INT
+trap onexit TERM
+trap onexit EXIT
+
+TMPDIR=
+
+onexit()
+{
+	if [ ! "$TMPDIR" = "" ]; then
+		sudo rm -rf $TMPDIR
+	fi
+}
+
+usage()
+{
+	echo "$0 [universal [32-bit build dir]]"
+	exit 1
+}
+
+UNIVERSAL=0
+
+PACKAGE_NAME=@PACKAGE_NAME@
+VERSION=@VERSION@
+BUILD=@BUILD@
+SRCDIR=@abs_top_srcdir@
+BUILDDIR32=@abs_top_srcdir@/osxx86
+if [ $# -gt 0 ]; then
+	if [ "$1" = "universal" ]; then
+		UNIVERSAL=1
+		if [ $# -gt 1 ]; then BUILDDIR32=$2; fi
+	fi
+fi
+PACKAGEMAKER=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker
+
+if [ -f $PACKAGE_NAME-$VERSION.dmg ]; then
+	rm -f $PACKAGE_NAME-$VERSION.dmg
+fi
+
+umask 022
+TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
+PKGROOT=$TMPDIR/pkg/Package_Root
+mkdir -p $PKGROOT
+mkdir -p $PKGROOT/opt/$PACKAGE_NAME/bin
+make install DESTDIR=$PKGROOT mandir=/opt/$PACKAGE_NAME/man
+rm -f $PKGROOT/opt/$PACKAGE_NAME/lib/*.la
+mkdir -p $PKGROOT/usr/lib
+mv $PKGROOT/opt/$PACKAGE_NAME/lib/libturbojpeg.* $PKGROOT/usr/lib
+mkdir -p $PKGROOT/usr/include
+mv $PKGROOT/opt/$PACKAGE_NAME/include/turbojpeg.h $PKGROOT/usr/include
+
+if [ $UNIVERSAL = 1 ]; then
+	if [ ! -d $BUILDDIR32 ]; then
+		echo ERROR: 32-bit build directory $BUILDDIR32 does not exist
+		exit 1
+	fi
+	if [ ! -f $BUILDDIR32/Makefile ]; then
+		echo ERROR: 32-bit build directory $BUILDDIR32 is not configured
+		exit 1
+	fi
+	mkdir -p $TMPDIR/dist.x86
+	pushd $BUILDDIR32
+	make install DESTDIR=$TMPDIR/dist.x86
+	popd
+	if [ ! -h $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib -a \
+		! -h $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib ]; then
+		lipo -create \
+			-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib \
+			-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib \
+			-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib
+	elif [ ! -h $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@.dylib -a \
+		! -h $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@.dylib ]; then
+		lipo -create \
+			-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@.dylib \
+			-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@.dylib \
+			-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@.dylib
+	fi
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libjpeg.a \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.a \
+		-output $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.a
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libturbojpeg.dylib \
+		-arch x86_64 $PKGROOT/usr/lib/libturbojpeg.dylib \
+		-output $PKGROOT/usr/lib/libturbojpeg.dylib
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/lib/libturbojpeg.a \
+		-arch x86_64 $PKGROOT/usr/lib/libturbojpeg.a \
+		-output $PKGROOT/usr/lib/libturbojpeg.a
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/cjpeg \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/cjpeg \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/cjpeg
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/djpeg \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/djpeg \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/djpeg
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/jpegtran \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/jpegtran \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/jpegtran
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/jpgtest \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/jpgtest \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/jpgtest
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/rdjpgcom \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/rdjpgcom \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/rdjpgcom
+	lipo -create \
+		-arch i386 $TMPDIR/dist.x86/opt/$PACKAGE_NAME/bin/wrjpgcom \
+		-arch x86_64 $PKGROOT/opt/$PACKAGE_NAME/bin/wrjpgcom \
+		-output $PKGROOT/opt/$PACKAGE_NAME/bin/wrjpgcom
+
+fi
+
+install_name_tool -id /opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib $PKGROOT/opt/$PACKAGE_NAME/lib/libjpeg.@SO_MAJOR_VERSION@.dylib
+install_name_tool -id libturbojpeg.dylib $PKGROOT/usr/lib/libturbojpeg.dylib
+
+ln -fs /usr/include/turbojpeg.h $PKGROOT/opt/$PACKAGE_NAME/include/
+ln -fs /usr/lib/libturbojpeg.a $PKGROOT/opt/$PACKAGE_NAME/lib/
+if [ ! -h $PKGROOT/opt/$PACKAGE_NAME/lib32 ]; then
+	ln -fs lib $PKGROOT/opt/$PACKAGE_NAME/lib32
+fi
+if [ ! -h $PKGROOT/opt/$PACKAGE_NAME/lib64 ]; then
+	ln -fs lib $PKGROOT/opt/$PACKAGE_NAME/lib64
+fi
+
+mkdir -p $PKGROOT/Library/Documentation/$PACKAGE_NAME
+chmod 1775 $PKGROOT/Library
+chmod 775 $PKGROOT/Library/Documentation 
+mkdir -p $TMPDIR/pkg/Resources 
+
+cp pkgscripts/Description.plist $TMPDIR/pkg/
+cp pkgscripts/Info.plist $TMPDIR/pkg/
+install -m 755 pkgscripts/uninstall $PKGROOT/opt/$PACKAGE_NAME/bin/
+
+install -m 644 $SRCDIR/LICENSE.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/LICENSE.txt 
+install -m 644 $SRCDIR/LGPL.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/LGPL.txt 
+install -m 644 $SRCDIR/README-turbo.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/README-turbo.txt 
+install -m 644 $SRCDIR/README $PKGROOT/Library/Documentation/$PACKAGE_NAME/README 
+install -m 644 $SRCDIR/libjpeg.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/libjpeg.txt 
+install -m 644 $SRCDIR/usage.txt $PKGROOT/Library/Documentation/$PACKAGE_NAME/usage.txt 
+
+sudo chown -R root:admin $PKGROOT 
+sudo chown -R root:0 $PKGROOT/usr 
+cp $SRCDIR/release/License.rtf $SRCDIR/release/Welcome.rtf $SRCDIR/release/ReadMe.rtf $TMPDIR/pkg/Resources/ 
+
+mkdir $TMPDIR/dmg
+$PACKAGEMAKER -build -v -p $TMPDIR/dmg/$PACKAGE_NAME.pkg \
+	-f $PKGROOT -r $TMPDIR/pkg/Resources \
+	-i $TMPDIR/pkg/Info.plist -d $TMPDIR/pkg/Description.plist 
+install -m 644 $SRCDIR/release/uninstall.applescript $TMPDIR 
+sudo osacompile -t APPL -o "$TMPDIR/dmg/Uninstall $PACKAGE_NAME.app" $TMPDIR/uninstall.applescript 
+sudo chown -R $USER "$TMPDIR/dmg/Uninstall $PACKAGE_NAME.app" 
+hdiutil create -fs HFS+ -volname $PACKAGE_NAME-$VERSION \
+	-srcfolder "$TMPDIR/dmg" $TMPDIR/$PACKAGE_NAME-$VERSION.dmg 
+cp $TMPDIR/$PACKAGE_NAME-$VERSION.dmg . 
+
+exit
diff --git a/release/makerpm b/release/makerpm
deleted file mode 100644
index 8aee3a0..0000000
--- a/release/makerpm
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/bin/sh
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-TMPDIR=
-
-onexit()
-{
-	if [ ! "$TMPDIR" = "" ]; then
-		rm -rf $TMPDIR
-	fi
-}
-
-usage()
-{
-	echo "$0 <package name> <version> <build> <RPM architecture> <source dir.>"
-	exit 1
-}
-
-if [ $# -lt 5 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-BUILD=$3
-RPMARCH=$4
-SRCDIR=$5
-
-TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
-mkdir -p $TMPDIR/RPMS
-ln -fs `pwd` $TMPDIR/BUILD
-rm -f $PACKAGE_NAME.$RPMARCH.rpm
-rpmbuild -bb --define "_name $PACKAGE_NAME" \
-	--define "_blddir $TMPDIR/buildroot" --define "_topdir $TMPDIR" \
-	--define "_version $VERSION" --define "_build $BUILD" \
-	--define "_srcdir $SRCDIR" --target $RPMARCH \
-	$SRCDIR/release/libjpeg-turbo.spec
-cp $TMPDIR/RPMS/$RPMARCH/$PACKAGE_NAME-$VERSION-$BUILD.$RPMARCH.rpm $PACKAGE_NAME.$RPMARCH.rpm
-
-exit
diff --git a/release/makesrpm b/release/makesrpm
deleted file mode 100644
index bb31832..0000000
--- a/release/makesrpm
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/sh
-
-set -u
-set -e
-trap onexit INT
-trap onexit TERM
-trap onexit EXIT
-
-TMPDIR=
-
-onexit()
-{
-	if [ ! "$TMPDIR" = "" ]; then
-		rm -rf $TMPDIR
-	fi
-}
-
-usage()
-{
-	echo "$0 <package name> <version> <build> <RPM architecture> <source dir.>"
-	exit 1
-}
-
-if [ $# -lt 4 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-BUILD=$3
-SRCDIR=$4
-
-TARBALL=$PACKAGE_NAME-$VERSION.tar.gz
-if [ ! -f ./$TARBALL ]; then
-	echo ./$TARBALL does not exist.  Run make dist-gzip first.
-	exit -1
-fi
-
-TMPDIR=`mktemp -d /tmp/$PACKAGE_NAME-build.XXXXXX`
-mkdir -p $TMPDIR/RPMS
-mkdir -p $TMPDIR/SRPMS
-mkdir -p $TMPDIR/BUILD
-mkdir -p $TMPDIR/SOURCES
-mkdir -p $TMPDIR/SPECS
-rm -f $PACKAGE_NAME.src.rpm
-cp $TARBALL $TMPDIR/SOURCES
-cat $SRCDIR/release/libjpeg-turbo.spec | sed s/%{_name}/$PACKAGE_NAME/g \
-	| sed s/%{_version}/$VERSION/g | sed s/%{_build}/$BUILD/g \
-	| sed s/%{_blddir}/%{_tmppath}/g | sed s@%{_srcdir}/@@g \
-	| sed s/#--\>//g >$TMPDIR/SPECS/libjpeg-turbo.spec
-rpmbuild -bs --define "_topdir $TMPDIR" $TMPDIR/SPECS/libjpeg-turbo.spec
-cp $TMPDIR/SRPMS/$PACKAGE_NAME-$VERSION-$BUILD.src.rpm $PACKAGE_NAME.src.rpm
-
-exit
diff --git a/release/makesunpkg b/release/makesunpkg.in
similarity index 66%
rename from release/makesunpkg
rename to release/makesunpkg.in
index 2bc40d4..aa2e735 100644
--- a/release/makesunpkg
+++ b/release/makesunpkg.in
@@ -17,22 +17,23 @@
 
 usage()
 {
-	echo "$0 <package name> <version> <build> <package architecture> <source dir.> [combined]"
+	echo "$0 [combined [32-bit build dir.]]"
 	exit 1
 }
 
 COMBINED=0
 
-if [ $# -lt 4 ]; then usage $0; fi
-PACKAGE_NAME=$1
-VERSION=$2
-BUILD=$3
-PKGARCH=$4
-SRCDIR=$5
-CC=$6
-CXX=$7
-if [ $# -gt 7 ]; then
-	if [ "$8" = "combined" ]; then COMBINED=1; fi
+PACKAGE_NAME=@PACKAGE_NAME@
+VERSION=@VERSION@
+BUILD=@BUILD@
+PKGARCH=@DEBARCH@
+SRCDIR=@abs_top_srcdir@
+BUILDDIR32=@abs_top_srcdir@/solx86
+if [ $# -gt 0 ]; then
+	if [ "$1" = "combined" ]; then
+		COMBINED=1
+		if [ $# -gt 1 ]; then	BUILDDIR32=$2; fi
+	fi
 fi
 
 umask 022
@@ -40,9 +41,7 @@
 rm -f $PACKAGE_NAME.pkg.bz2
 cp $SRCDIR/release/copyright $TMPDIR
 touch $TMPDIR/depend
-cat $SRCDIR/release/pkginfo.tmpl | sed s/{__VERSION}/$VERSION/g \
-	| sed s/{__BUILD}/$BUILD/g | sed s/{__APPNAME}/$PACKAGE_NAME/g \
-	| sed s/{__PKGNAME}/$PACKAGE_NAME/g > $TMPDIR/pkginfo 
+cp pkgscripts/pkginfo $TMPDIR/pkginfo 
 
 if [ "$PKGARCH" = "i386" ]; then
 	__LIB=lib
@@ -50,21 +49,25 @@
 	__LIB=lib/$PKGARCH
 fi
 
-# This mess is to work around a bug in /usr/ccs/bin/make
 if [ $COMBINED = 1 ]; then
-	if [ ! -d $SRCDIR/solx86 ]; then
-		mkdir -p $SRCDIR/solx86
+	if [ ! -d $BUILDDIR32 ]; then
+		echo ERROR: 32-bit build directory $BUILDDIR32 does not exist
+		exit 1
+	fi
+	if [ ! -f $BUILDDIR32/Makefile ]; then
+		echo ERROR: 32-bit build directory $BUILDDIR32 is not configured
+		exit 1
 	fi
 	PWD=`pwd`
-	cd $SRCDIR/solx86
-	sh $SRCDIR/configure --with-pic CC=$CC CXX=$CXX CFLAGS= CXXFLAGS= LDFLAGS= host_alias=
+	cd $BUILDDIR32
 	make install DESTDIR=$TMPDIR mandir=/opt/$PACKAGE_NAME/man AM_MAKEFLAGS="mandir=/opt/$PACKAGE_NAME/man"
 	cd $PWD
 fi
+# This mess is to work around a bug in /usr/ccs/bin/make
 make install DESTDIR=$TMPDIR libdir=/opt/$PACKAGE_NAME/$__LIB mandir=/opt/$PACKAGE_NAME/man AM_MAKEFLAGS="libdir=/opt/$PACKAGE_NAME/$__LIB mandir=/opt/$PACKAGE_NAME/man"
 rm -f $TMPDIR/opt/$PACKAGE_NAME/$__LIB/*.la
 mkdir -p $TMPDIR/opt/$PACKAGE_NAME/doc
-cp $SRCDIR/LICENSE.txt $SRCDIR/LGPL.txt $SRCDIR/README-turbo.txt $SRCDIR/README $SRCDIR/libjpeg.doc $SRCDIR/usage.doc $TMPDIR/opt/$PACKAGE_NAME/doc
+cp $SRCDIR/LICENSE.txt $SRCDIR/LGPL.txt $SRCDIR/README-turbo.txt $SRCDIR/README $SRCDIR/libjpeg.txt $SRCDIR/usage.txt $TMPDIR/opt/$PACKAGE_NAME/doc
 chmod 644 $TMPDIR/opt/$PACKAGE_NAME/doc/*
 
 cat >$TMPDIR/proto <<EOF
@@ -76,15 +79,16 @@
 f none $PACKAGE_NAME/bin/cjpeg 0755 root bin
 f none $PACKAGE_NAME/bin/djpeg 0755 root bin
 f none $PACKAGE_NAME/bin/jpegtran 0755 root bin
+f none $PACKAGE_NAME/bin/jpgtest 0755 root bin
 f none $PACKAGE_NAME/bin/rdjpgcom 0755 root bin
 f none $PACKAGE_NAME/bin/wrjpgcom 0755 root bin
 d none $PACKAGE_NAME/lib 0755 root bin
 EOF
 if [ $COMBINED = 1 ]; then
 cat >>$TMPDIR/proto <<EOF
-f none $PACKAGE_NAME/lib/libjpeg.so.62.0.0 0755 root bin
-s none $PACKAGE_NAME/lib/libjpeg.so.62=libjpeg.so.62.0.0
-s none $PACKAGE_NAME/lib/libjpeg.so=libjpeg.so.62.0.0
+f none $PACKAGE_NAME/lib/libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@ 0755 root bin
+s none $PACKAGE_NAME/lib/libjpeg.so.@SO_MAJOR_VERSION@=libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@
+s none $PACKAGE_NAME/lib/libjpeg.so=libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@
 f none $PACKAGE_NAME/lib/libjpeg.a 0644 root bin
 f none $PACKAGE_NAME/lib/libturbojpeg.so 0755 root bin
 f none $PACKAGE_NAME/lib/libturbojpeg.a 0644 root bin
@@ -96,9 +100,9 @@
 echo s none $PACKAGE_NAME/lib/64=$PKGARCH >>$TMPDIR/proto
 fi
 cat >>$TMPDIR/proto <<EOF
-f none $PACKAGE_NAME/${__LIB}/libjpeg.so.62.0.0 0755 root bin
-s none $PACKAGE_NAME/${__LIB}/libjpeg.so.62=libjpeg.so.62.0.0
-s none $PACKAGE_NAME/${__LIB}/libjpeg.so=libjpeg.so.62.0.0
+f none $PACKAGE_NAME/${__LIB}/libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@ 0755 root bin
+s none $PACKAGE_NAME/${__LIB}/libjpeg.so.@SO_MAJOR_VERSION@=libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@
+s none $PACKAGE_NAME/${__LIB}/libjpeg.so=libjpeg.so.@SO_MAJOR_VERSION@.0.@SO_MINOR_VERSION@
 f none $PACKAGE_NAME/${__LIB}/libjpeg.a 0644 root bin
 f none $PACKAGE_NAME/${__LIB}/libturbojpeg.so 0755 root bin
 f none $PACKAGE_NAME/${__LIB}/libturbojpeg.a 0644 root bin
@@ -118,16 +122,16 @@
 f none $PACKAGE_NAME/include/turbojpeg.h 0644 root bin
 d none $PACKAGE_NAME/doc 0755 root bin
 f none $PACKAGE_NAME/doc/LGPL.txt 0644 root bin
-f none $PACKAGE_NAME/doc/libjpeg.doc 0644 root bin
+f none $PACKAGE_NAME/doc/libjpeg.txt 0644 root bin
 f none $PACKAGE_NAME/doc/LICENSE.txt 0644 root bin
 f none $PACKAGE_NAME/doc/README 0644 root bin
 f none $PACKAGE_NAME/doc/README-turbo.txt 0644 root bin
-f none $PACKAGE_NAME/doc/usage.doc 0644 root bin
+f none $PACKAGE_NAME/doc/usage.txt 0644 root bin
 EOF
 
 pkgmk -o -r $TMPDIR/opt -d $TMPDIR -a i386 -f $TMPDIR/proto
-pkgtrans -s $TMPDIR $TMPDIR/$PACKAGE_NAME.pkg $PACKAGE_NAME
-bzip2 $TMPDIR/$PACKAGE_NAME.pkg
-cp $TMPDIR/$PACKAGE_NAME.pkg.bz2 . 
+pkgtrans -s $TMPDIR $TMPDIR/$PACKAGE_NAME-$VERSION.pkg $PACKAGE_NAME
+bzip2 $TMPDIR/$PACKAGE_NAME-$VERSION.pkg
+cp $TMPDIR/$PACKAGE_NAME-$VERSION.pkg.bz2 . 
 
 exit
diff --git a/release/pkginfo.in b/release/pkginfo.in
new file mode 100644
index 0000000..772ad0f
--- /dev/null
+++ b/release/pkginfo.in
@@ -0,0 +1,16 @@
+ARCH=i386
+PKG=@PACKAGE_NAME@
+NAME=@PACKAGE_NAME@ SDK and run time libraries
+VERSION=@VERSION@,REV=@BUILD@
+SUNW_PKGVERS=1.0
+DESC=A SIMD-accelerated JPEG codec that provides both the libjpeg and TurboJPEG APIs
+VENDOR=The libjpeg-turbo Project
+HOTLINE=http://www.libjpeg-turbo.org
+EMAIL=information@libjpeg-turbo.org
+MAXINST=1
+CATEGORY=application
+BASEDIR=/opt
+CLASSES=none
+SUNW_PKG_ALLZONES=true
+SUNW_PKG_HOLLOW=false
+SUNW_PKG_THISZONE=false
diff --git a/release/pkginfo.tmpl b/release/pkginfo.tmpl
deleted file mode 100644
index b53d5f4..0000000
--- a/release/pkginfo.tmpl
+++ /dev/null
@@ -1,16 +0,0 @@
-ARCH=i386
-PKG={__PKGNAME}
-NAME={__APPNAME} SDK and run time libraries
-VERSION={__VERSION},REV={__BUILD}
-SUNW_PKGVERS=1.0
-DESC=A SIMD-accelerated JPEG codec which provides both the libjpeg and TurboJPEG APIs
-VENDOR=The libjpeg-turbo Project
-HOTLINE=http://www.libjpeg-turbo.org
-EMAIL=information@libjpeg-turbo.org
-MAXINST=1
-CATEGORY=application
-BASEDIR=/opt
-CLASSES=none
-SUNW_PKG_ALLZONES=true
-SUNW_PKG_HOLLOW=false
-SUNW_PKG_THISZONE=false
diff --git a/release/uninstall.sh.tmpl b/release/uninstall.in
similarity index 96%
rename from release/uninstall.sh.tmpl
rename to release/uninstall.in
index ed8846b..94fc4f1 100644
--- a/release/uninstall.sh.tmpl
+++ b/release/uninstall.in
@@ -1,4 +1,4 @@
-# Copyright (C)2009-2010 D. R. Commander
+# Copyright (C)2009-2011 D. R. Commander
 # Copyright (C)2009 Sun Microsystems, Inc.
 #
 # This library is free software and may be redistributed and/or modified under
@@ -23,7 +23,7 @@
 	error "This command must be run as root"
 fi
 
-PKGNAME={__APPNAME}
+PKGNAME=@PACKAGE_NAME@
 MACPKGNAME=com.$PKGNAME.$PKGNAME
 RCPT=/Library/Receipts/$PKGNAME.pkg
 
diff --git a/rrtimer.h b/rrtimer.h
index 4db5e37..3031ef5 100644
--- a/rrtimer.h
+++ b/rrtimer.h
@@ -15,69 +15,6 @@
 #ifndef __RRTIMER_H__
 #define __RRTIMER_H__
 
-#ifdef __cplusplus
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <sys/time.h>
-#endif
-
-class rrtimer
-{
-	public:
-
-		rrtimer(void) : t1(0.0)
-		{
-			#ifdef _WIN32
-			highres=false;  tick=0.001;
-			LARGE_INTEGER Frequency;
-			if(QueryPerformanceFrequency(&Frequency)!=0)
-			{
-				tick=(double)1.0/(double)(Frequency.QuadPart);
-				highres=true;
-			}
-			#endif
-		}
-
-		void start(void)
-		{
-			t1=time();
-		}
-
-		double time(void)
-		{
-			#ifdef _WIN32
-			if(highres)
-			{
-				LARGE_INTEGER Time;
-				QueryPerformanceCounter(&Time);
-				return((double)(Time.QuadPart)*tick);
-			}
-			else
-				return((double)GetTickCount()*tick);
-			#else
-			struct timeval __tv;
-			gettimeofday(&__tv, (struct timezone *)NULL);
-			return((double)(__tv.tv_sec)+(double)(__tv.tv_usec)*0.000001);
-			#endif
-		}
-
-		double elapsed(void)
-		{
-			return time()-t1;
-		}
-
-	private:
-
-		#ifdef _WIN32
-		bool highres;  double tick;
-		#endif
-		double t1;
-};
-
-#endif  // __cplusplus
-
 #ifdef _WIN32
 
 #include <windows.h>
@@ -111,4 +48,3 @@
 #endif
 
 #endif
-
diff --git a/sharedlib/CMakeLists.txt b/sharedlib/CMakeLists.txt
new file mode 100755
index 0000000..97e06e3
--- /dev/null
+++ b/sharedlib/CMakeLists.txt
@@ -0,0 +1,59 @@
+# Anything that must be linked against the shared C library on Windows must
+# be built in this subdirectory, because CMake doesn't allow us to override
+# the compiler flags for each build type except at directory scope.  Note
+# to CMake developers:  Add a COMPILE_FLAGS_<CONFIG> target property, or
+# better yet, provide a friendly way of configuring a Windows target to use the
+# static C library.
+
+if(MSVC)
+  # Build all configurations against shared C library
+  foreach(var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+    if(${var} MATCHES "/MT")
+      string(REGEX REPLACE "/MT" "/MD" ${var} "${${var}}")
+    endif()
+  endforeach()
+endif()
+
+foreach(src ${JPEG_SOURCES})
+  set(JPEG_SRCS ${JPEG_SRCS} ${CMAKE_SOURCE_DIR}/${src})
+endforeach()
+
+if(WITH_SIMD)
+  # This tells CMake that the "source" files haven't been generated yet
+  set_source_files_properties(${SIMD_OBJS} PROPERTIES GENERATED 1)
+endif()
+
+add_library(jpeg SHARED ${JPEG_SRCS} ${SIMD_OBJS}
+  ${CMAKE_SOURCE_DIR}/win/jpeg${DLL_VERSION}.def)
+set_target_properties(jpeg PROPERTIES SOVERSION ${DLL_VERSION}
+  VERSION ${FULLVERSION})
+if(MSVC)
+  set_target_properties(jpeg PROPERTIES SUFFIX ${DLL_VERSION}.dll)
+elseif(MINGW OR CYGWIN)
+  set_target_properties(jpeg PROPERTIES SUFFIX -${DLL_VERSION}.dll)
+endif(MSVC)
+if(WITH_SIMD)
+  add_dependencies(jpeg simd)
+endif()
+
+add_executable(cjpeg ../cjpeg.c ../cdjpeg.c ../rdbmp.c ../rdgif.c ../rdppm.c
+  ../rdswitch.c ../rdtarga.c)
+set_property(TARGET cjpeg PROPERTY COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED -DUSE_SETMODE")
+target_link_libraries(cjpeg jpeg)
+
+add_executable(djpeg ../djpeg.c ../cdjpeg.c ../rdcolmap.c ../rdswitch.c
+  ../wrbmp.c ../wrgif.c ../wrppm.c ../wrtarga.c)
+set_property(TARGET djpeg PROPERTY COMPILE_FLAGS
+  "-DBMP_SUPPORTED -DGIF_SUPPORTED -DPPM_SUPPORTED -DTARGA_SUPPORTED -DUSE_SETMODE")
+target_link_libraries(djpeg jpeg)
+
+add_executable(jpegtran ../jpegtran.c ../cdjpeg.c ../rdswitch.c ../transupp.c)
+target_link_libraries(jpegtran jpeg)
+set_property(TARGET jpegtran PROPERTY COMPILE_FLAGS "-DUSE_SETMODE")
+
+install(TARGETS jpeg cjpeg djpeg jpegtran
+  ARCHIVE DESTINATION lib
+  LIBRARY DESTINATION lib
+  RUNTIME DESTINATION bin)
diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt
new file mode 100755
index 0000000..d956dac
--- /dev/null
+++ b/simd/CMakeLists.txt
@@ -0,0 +1,58 @@
+if(NOT DEFINED NASM)
+  set(NASM nasm CACHE PATH "Path to NASM/YASM executable")
+endif()
+
+if(SIMD_X86_64)
+  set(NAFLAGS -fwin64 -DWIN64 -D__x86_64__ -I${CMAKE_SOURCE_DIR}/win/
+    -I${CMAKE_CURRENT_SOURCE_DIR}/)
+else()
+  set(NAFLAGS -fwin32 -DWIN32 -I${CMAKE_SOURCE_DIR}/win/
+    -I${CMAKE_CURRENT_SOURCE_DIR}/)
+endif()
+
+# This only works if building from the command line.  There is currently no way
+# to set a variable's value based on the build type when using the MSVC IDE.
+if(CMAKE_BUILD_TYPE STREQUAL "Debug"
+  OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+  set(NAFLAGS ${NAFLAGS} -g)
+endif()
+
+if(SIMD_X86_64)
+  set(SIMD_BASENAMES jfsseflt-64 jccolss2-64 jdcolss2-64 jcsamss2-64
+    jdsamss2-64 jdmerss2-64 jcqnts2i-64 jfss2fst-64 jfss2int-64 jiss2red-64
+    jiss2int-64 jiss2fst-64 jcqnts2f-64 jiss2flt-64)
+  message(STATUS "Building x86_64 SIMD extensions")
+else()
+  set(SIMD_BASENAMES jsimdcpu jccolmmx jdcolmmx jcsammmx jdsammmx jdmermmx
+    jcqntmmx jfmmxfst jfmmxint jimmxred jimmxint jimmxfst jcqnt3dn jf3dnflt
+    ji3dnflt jcqntsse jfsseflt jisseflt jccolss2 jdcolss2 jcsamss2 jdsamss2
+    jdmerss2 jcqnts2i jfss2fst jfss2int jiss2red jiss2int jiss2fst jcqnts2f
+    jiss2flt)
+  message(STATUS "Building i386 SIMD extensions")
+endif()
+
+if(MSVC_IDE)
+  set(OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}")
+else()
+  set(OBJDIR ${CMAKE_CURRENT_BINARY_DIR})
+endif()
+
+foreach(file ${SIMD_BASENAMES})
+  set(DEPFILE "")
+  set(SIMD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${file}.asm)
+  if(${file} MATCHES col)
+    set(DEPFILE ${SIMD_SRC})
+    string(REGEX REPLACE "col" "clr" DEPFILE ${DEPFILE})
+  endif()
+  if(${file} MATCHES mer)
+    set(DEPFILE ${SIMD_SRC})
+    string(REGEX REPLACE "mer" "mrg" DEPFILE ${DEPFILE})
+  endif()
+  set(SIMD_OBJ ${OBJDIR}/${file}.obj)
+  add_custom_command(OUTPUT ${SIMD_OBJ} DEPENDS ${SIMD_SRC} ${DEPFILE} *.inc
+    COMMAND ${NASM} ${NAFLAGS} ${SIMD_SRC} -o${SIMD_OBJ})
+  set(SIMD_OBJS ${SIMD_OBJS} ${SIMD_OBJ})
+endforeach()
+
+set(SIMD_OBJS ${SIMD_OBJS} PARENT_SCOPE)
+add_custom_target(simd DEPENDS ${SIMD_OBJS})
diff --git a/simd/Makefile.am b/simd/Makefile.am
index a114c37..81c23af 100644
--- a/simd/Makefile.am
+++ b/simd/Makefile.am
@@ -4,7 +4,7 @@
 
 EXTRA_DIST = nasm_lt.sh jcclrmmx.asm jcclrss2.asm jdclrmmx.asm jdclrss2.asm \
 	jdmrgmmx.asm jdmrgss2.asm jcclrss2-64.asm jdclrss2-64.asm \
-	jdmrgss2-64.asm
+	jdmrgss2-64.asm CMakeLists.txt
 
 if SIMD_X86_64
 
diff --git a/simd/jsimd_i386.c b/simd/jsimd_i386.c
index d9bb774..021bcb2 100644
--- a/simd/jsimd_i386.c
+++ b/simd/jsimd_i386.c
@@ -41,7 +41,7 @@
 {
   char *env = NULL;
 
-  if (simd_support != ~0)
+  if (simd_support != ~0U)
     return;
 
   simd_support = jpeg_simd_cpu_support();
diff --git a/simd/jsimdext.inc b/simd/jsimdext.inc
index 12a04c2..10a727f 100644
--- a/simd/jsimdext.inc
+++ b/simd/jsimdext.inc
@@ -299,8 +299,6 @@
 %ifdef WIN64
 
 %imacro collect_args 0
-	push r10
-	push r11
 	push r12
 	push r13
 	push r14
@@ -330,8 +328,6 @@
 	pop r14
 	pop r13
 	pop r12
-	pop r11
-	pop r10
 %endmacro
 
 %else
diff --git a/structure.doc b/structure.txt
similarity index 97%
rename from structure.doc
rename to structure.txt
index 51c9def..6a9266b 100644
--- a/structure.doc
+++ b/structure.txt
@@ -1,6 +1,6 @@
 IJG JPEG LIBRARY:  SYSTEM ARCHITECTURE
 
-Copyright (C) 1991-1995, Thomas G. Lane.
+Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
 This file is part of the Independent JPEG Group's software.
 For conditions of distribution and use, see the accompanying README file.
 
@@ -12,9 +12,9 @@
 
 We assume that the reader is already somewhat familiar with the JPEG standard.
 The README file includes references for learning about JPEG.  The file
-libjpeg.doc describes the library from the viewpoint of an application
+libjpeg.txt describes the library from the viewpoint of an application
 programmer using the library; it's best to read that file before this one.
-Also, the file coderules.doc describes the coding style conventions we use.
+Also, the file coderules.txt describes the coding style conventions we use.
 
 In this document, JPEG-specific terminology follows the JPEG standard:
   A "component" means a color channel, e.g., Red or Luminance.
@@ -60,9 +60,6 @@
 run-time option, because most machines can store 8-bit pixels much more
 compactly than 12-bit.
 
-For legal reasons, JPEG arithmetic coding is not currently supported, but
-extending the library to include it would be straightforward.
-
 By itself, the library handles only interchange JPEG datastreams --- in
 particular the widely used JFIF file format.  The library can be used by
 surrounding code to process interchange or abbreviated JPEG datastreams that
@@ -388,8 +385,9 @@
 
 * Data destination manager: writes the output JPEG datastream to its final
   destination (e.g., a file).  The destination manager supplied with the
-  library knows how to write to a stdio stream; for other behaviors, the
-  surrounding application may provide its own destination manager.
+  library knows how to write to a stdio stream or to a memory buffer;
+  for other behaviors, the surrounding application may provide its own
+  destination manager.
 
 * Memory manager: allocates and releases memory, controls virtual arrays
   (with backing store management, where required).
@@ -507,9 +505,9 @@
 * Marker reading: decodes JPEG markers (except for RSTn).
 
 * Data source manager: supplies the input JPEG datastream.  The source
-  manager supplied with the library knows how to read from a stdio stream;
-  for other behaviors, the surrounding application may provide its own source
-  manager.
+  manager supplied with the library knows how to read from a stdio stream
+  or from a memory buffer;  for other behaviors, the surrounding application
+  may provide its own source manager.
 
 * Memory manager: same as for compression library.
 
@@ -541,7 +539,7 @@
 extra display passes when data is arriving faster than the display pass
 can run.  Furthermore, it is possible to abort an output pass without
 losing anything, since the coefficient buffer is read-only as far as the
-output section is concerned.  See libjpeg.doc for more detail.
+output section is concerned.  See libjpeg.txt for more detail.
 
 A full-image coefficient array is only created if the JPEG file has multiple
 scans (or if the application specifies buffered-image mode anyway).  When
@@ -589,8 +587,7 @@
 With these conventions, JSAMPLE values can be assumed to be >= 0.  This helps
 simplify correct rounding during downsampling, etc.  The JPEG standard's
 specification that sample values run from -128..127 is accommodated by
-subtracting 128 just as the sample value is copied into the source array for
-the DCT step (this will be an array of signed ints).  Similarly, during
+subtracting 128 from the sample value in the DCT step.  Similarly, during
 decompression the output of the IDCT step will be immediately shifted back to
 0..255.  (NB: different values are required when 12-bit samples are in use.
 The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be
@@ -685,7 +682,7 @@
 
 This scenario is supported for simple cases.  (For anything more complex, we
 recommend that the application "bite the bullet" and develop real multitasking
-capability.)  The libjpeg.doc file goes into more detail about the usage and
+capability.)  The libjpeg.txt file goes into more detail about the usage and
 limitations of this capability; here we address the implications for library
 structure.
 
@@ -733,13 +730,14 @@
 without causing problems; otherwise a 64K buffer would be needed in the worst
 case.)
 
-The JPEG marker writer currently does *not* cope with suspension.  I feel that
-this is not necessary; it is much easier simply to require the application to
-ensure there is enough buffer space before starting.  (An empty 2K buffer is
-more than sufficient for the header markers; and ensuring there are a dozen or
-two bytes available before calling jpeg_finish_compress() will suffice for the
-trailer.)  This would not work for writing multi-scan JPEG files, but
-we simply do not intend to support that capability with suspension.
+The JPEG marker writer currently does *not* cope with suspension.
+We feel that this is not necessary; it is much easier simply to require
+the application to ensure there is enough buffer space before starting.  (An
+empty 2K buffer is more than sufficient for the header markers; and ensuring
+there are a dozen or two bytes available before calling jpeg_finish_compress()
+will suffice for the trailer.)  This would not work for writing multi-scan
+JPEG files, but we simply do not intend to support that capability with
+suspension.
 
 
 *** Memory manager services ***
diff --git a/testimgari.jpg b/testimgari.jpg
new file mode 100644
index 0000000..8966487
--- /dev/null
+++ b/testimgari.jpg
Binary files differ
diff --git a/testimgari.ppm b/testimgari.ppm
new file mode 100644
index 0000000..d7b38f2
--- /dev/null
+++ b/testimgari.ppm
Binary files differ
diff --git a/testimgcrop.jpg b/testimgcrop.jpg
new file mode 100644
index 0000000..18fa0b1
--- /dev/null
+++ b/testimgcrop.jpg
Binary files differ
diff --git a/transupp.c b/transupp.c
index e5ec564..5c31416 100644
--- a/transupp.c
+++ b/transupp.c
@@ -1,7 +1,8 @@
 /*
  * transupp.c
  *
- * Copyright (C) 1997, Thomas G. Lane.
+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
+ * Copyright (C) 2010, D. R. Commander.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -20,6 +21,17 @@
 #include "jinclude.h"
 #include "jpeglib.h"
 #include "transupp.h"		/* My own external interface */
+#include "jpegcomp.h"
+#include <ctype.h>		/* to declare isdigit() */
+
+
+#if JPEG_LIB_VERSION >= 70
+#define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size
+#define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size
+#else
+#define dstinfo_min_DCT_h_scaled_size DCTSIZE
+#define dstinfo_min_DCT_v_scaled_size DCTSIZE
+#endif
 
 
 #if TRANSFORMS_SUPPORTED
@@ -28,7 +40,8 @@
  * Lossless image transformation routines.  These routines work on DCT
  * coefficient arrays and thus do not require any lossy decompression
  * or recompression of the image.
- * Thanks to Guido Vollbeding for the initial design and code of this feature.
+ * Thanks to Guido Vollbeding for the initial design and code of this feature,
+ * and to Ben Jackson for introducing the cropping feature.
  *
  * Horizontal flipping is done in-place, using a single top-to-bottom
  * pass through the virtual source array.  It will thus be much the
@@ -42,6 +55,13 @@
  * arrays for most of the transforms.  That could result in much thrashing
  * if the image is larger than main memory.
  *
+ * If cropping or trimming is involved, the destination arrays may be smaller
+ * than the source arrays.  Note it is not possible to do horizontal flip
+ * in-place when a nonzero Y crop offset is specified, since we'd have to move
+ * data from one block row to another but the virtual array manager doesn't
+ * guarantee we can touch more than one row at a time.  So in that case,
+ * we have to use a separate destination array.
+ *
  * Some notes about the operating environment of the individual transform
  * routines:
  * 1. Both the source and destination virtual arrays are allocated from the
@@ -54,20 +74,65 @@
  *    and we may as well take that as the effective iMCU size.
  * 4. When "trim" is in effect, the destination's dimensions will be the
  *    trimmed values but the source's will be untrimmed.
- * 5. All the routines assume that the source and destination buffers are
+ * 5. When "crop" is in effect, the destination's dimensions will be the
+ *    cropped values but the source's will be uncropped.  Each transform
+ *    routine is responsible for picking up source data starting at the
+ *    correct X and Y offset for the crop region.  (The X and Y offsets
+ *    passed to the transform routines are measured in iMCU blocks of the
+ *    destination.)
+ * 6. All the routines assume that the source and destination buffers are
  *    padded out to a full iMCU boundary.  This is true, although for the
  *    source buffer it is an undocumented property of jdcoefct.c.
- * Notes 2,3,4 boil down to this: generally we should use the destination's
- * dimensions and ignore the source's.
  */
 
 
 LOCAL(void)
-do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
-	   jvirt_barray_ptr *src_coef_arrays)
-/* Horizontal flip; done in-place, so no separate dest array is required */
+do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	 JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+	 jvirt_barray_ptr *src_coef_arrays,
+	 jvirt_barray_ptr *dst_coef_arrays)
+/* Crop.  This is only used when no rotate/flip is requested with the crop. */
 {
-  JDIMENSION MCU_cols, comp_width, blk_x, blk_y;
+  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
+  int ci, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  jpeg_component_info *compptr;
+
+  /* We simply have to copy the right amount of data (the destination's
+   * image size) starting at the given X and Y offsets in the source.
+   */
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	 dst_blk_y + y_crop_blocks,
+	 (JDIMENSION) compptr->v_samp_factor, FALSE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+			dst_buffer[offset_y],
+			compptr->width_in_blocks);
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+		   JDIMENSION x_crop_offset,
+		   jvirt_barray_ptr *src_coef_arrays)
+/* Horizontal flip; done in-place, so no separate dest array is required.
+ * NB: this only works when y_crop_offset is zero.
+ */
+{
+  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
   int ci, k, offset_y;
   JBLOCKARRAY buffer;
   JCOEFPTR ptr1, ptr2;
@@ -79,17 +144,20 @@
    * mirroring by changing the signs of odd-numbered columns.
    * Partial iMCUs at the right edge are left untouched.
    */
-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+  MCU_cols = srcinfo->output_width /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
     for (blk_y = 0; blk_y < compptr->height_in_blocks;
 	 blk_y += compptr->v_samp_factor) {
       buffer = (*srcinfo->mem->access_virt_barray)
 	((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	/* Do the mirroring */
 	for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
 	  ptr1 = buffer[offset_y][blk_x];
 	  ptr2 = buffer[offset_y][comp_width - blk_x - 1];
@@ -105,6 +173,80 @@
 	    *ptr2++ = -temp1;
 	  }
 	}
+	if (x_crop_blocks > 0) {
+	  /* Now left-justify the portion of the data to be kept.
+	   * We can't use a single jcopy_block_row() call because that routine
+	   * depends on memcpy(), whose behavior is unspecified for overlapping
+	   * source and destination areas.  Sigh.
+	   */
+	  for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+	    jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
+			    buffer[offset_y] + blk_x,
+			    (JDIMENSION) 1);
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+LOCAL(void)
+do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+	   jvirt_barray_ptr *src_coef_arrays,
+	   jvirt_barray_ptr *dst_coef_arrays)
+/* Horizontal flip in general cropping case */
+{
+  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
+  int ci, k, offset_y;
+  JBLOCKARRAY src_buffer, dst_buffer;
+  JBLOCKROW src_row_ptr, dst_row_ptr;
+  JCOEFPTR src_ptr, dst_ptr;
+  jpeg_component_info *compptr;
+
+  /* Here we must output into a separate array because we can't touch
+   * different rows of a single virtual array simultaneously.  Otherwise,
+   * this is essentially the same as the routine above.
+   */
+  MCU_cols = srcinfo->output_width /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+
+  for (ci = 0; ci < dstinfo->num_components; ci++) {
+    compptr = dstinfo->comp_info + ci;
+    comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+	 dst_blk_y += compptr->v_samp_factor) {
+      dst_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+	 (JDIMENSION) compptr->v_samp_factor, TRUE);
+      src_buffer = (*srcinfo->mem->access_virt_barray)
+	((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	 dst_blk_y + y_crop_blocks,
+	 (JDIMENSION) compptr->v_samp_factor, FALSE);
+      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+	dst_row_ptr = dst_buffer[offset_y];
+	src_row_ptr = src_buffer[offset_y];
+	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+	  if (x_crop_blocks + dst_blk_x < comp_width) {
+	    /* Do the mirrorable blocks */
+	    dst_ptr = dst_row_ptr[dst_blk_x];
+	    src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+	    /* this unrolled loop doesn't need to know which row it's on... */
+	    for (k = 0; k < DCTSIZE2; k += 2) {
+	      *dst_ptr++ = *src_ptr++;	 /* copy even column */
+	      *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
+	    }
+	  } else {
+	    /* Copy last partial block(s) verbatim */
+	    jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+			    dst_row_ptr + dst_blk_x,
+			    (JDIMENSION) 1);
+	  }
+	}
       }
     }
   }
@@ -113,11 +255,13 @@
 
 LOCAL(void)
 do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	   jvirt_barray_ptr *src_coef_arrays,
 	   jvirt_barray_ptr *dst_coef_arrays)
 /* Vertical flip */
 {
   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JBLOCKROW src_row_ptr, dst_row_ptr;
@@ -131,33 +275,39 @@
    * of odd-numbered rows.
    * Partial iMCUs at the bottom edge are copied verbatim.
    */
-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+  MCU_rows = srcinfo->output_height /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
-      if (dst_blk_y < comp_height) {
+      if (y_crop_blocks + dst_blk_y < comp_height) {
 	/* Row is within the mirrorable area. */
 	src_buffer = (*srcinfo->mem->access_virt_barray)
 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
-	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
+	   comp_height - y_crop_blocks - dst_blk_y -
+	   (JDIMENSION) compptr->v_samp_factor,
 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
       } else {
 	/* Bottom-edge blocks will be copied verbatim. */
 	src_buffer = (*srcinfo->mem->access_virt_barray)
-	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	   dst_blk_y + y_crop_blocks,
 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
       }
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-	if (dst_blk_y < comp_height) {
+	if (y_crop_blocks + dst_blk_y < comp_height) {
 	  /* Row is within the mirrorable area. */
 	  dst_row_ptr = dst_buffer[offset_y];
 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+	  src_row_ptr += x_crop_blocks;
 	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
 	       dst_blk_x++) {
 	    dst_ptr = dst_row_ptr[dst_blk_x];
@@ -173,7 +323,8 @@
 	  }
 	} else {
 	  /* Just copy row verbatim. */
-	  jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y],
+	  jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+			  dst_buffer[offset_y],
 			  compptr->width_in_blocks);
 	}
       }
@@ -184,11 +335,12 @@
 
 LOCAL(void)
 do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	      JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	      jvirt_barray_ptr *src_coef_arrays,
 	      jvirt_barray_ptr *dst_coef_arrays)
 /* Transpose source into destination */
 {
-  JDIMENSION dst_blk_x, dst_blk_y;
+  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_x, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JCOEFPTR src_ptr, dst_ptr;
@@ -201,6 +353,8 @@
    */
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
@@ -210,11 +364,12 @@
 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
 	     dst_blk_x += compptr->h_samp_factor) {
 	  src_buffer = (*srcinfo->mem->access_virt_barray)
-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	     dst_blk_x + x_crop_blocks,
 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
-	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
 	    for (i = 0; i < DCTSIZE; i++)
 	      for (j = 0; j < DCTSIZE; j++)
 		dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -228,6 +383,7 @@
 
 LOCAL(void)
 do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	   jvirt_barray_ptr *src_coef_arrays,
 	   jvirt_barray_ptr *dst_coef_arrays)
 /* 90 degree rotation is equivalent to
@@ -237,6 +393,7 @@
  */
 {
   JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_x, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JCOEFPTR src_ptr, dst_ptr;
@@ -246,11 +403,14 @@
    * at the (output) right edge properly.  They just get transposed and
    * not mirrored.
    */
-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
+  MCU_cols = srcinfo->output_height /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_width = MCU_cols * compptr->h_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
@@ -259,15 +419,26 @@
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
 	     dst_blk_x += compptr->h_samp_factor) {
-	  src_buffer = (*srcinfo->mem->access_virt_barray)
-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
-	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  if (x_crop_blocks + dst_blk_x < comp_width) {
+	    /* Block is within the mirrorable area. */
+	    src_buffer = (*srcinfo->mem->access_virt_barray)
+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	       comp_width - x_crop_blocks - dst_blk_x -
+	       (JDIMENSION) compptr->h_samp_factor,
+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  } else {
+	    /* Edge blocks are transposed but not mirrored. */
+	    src_buffer = (*srcinfo->mem->access_virt_barray)
+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	       dst_blk_x + x_crop_blocks,
+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  }
 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
-	    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
-	    if (dst_blk_x < comp_width) {
+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	    if (x_crop_blocks + dst_blk_x < comp_width) {
 	      /* Block is within the mirrorable area. */
-	      dst_ptr = dst_buffer[offset_y]
-		[comp_width - dst_blk_x - offset_x - 1];
+	      src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+		[dst_blk_y + offset_y + y_crop_blocks];
 	      for (i = 0; i < DCTSIZE; i++) {
 		for (j = 0; j < DCTSIZE; j++)
 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -277,7 +448,8 @@
 	      }
 	    } else {
 	      /* Edge blocks are transposed but not mirrored. */
-	      dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	      src_ptr = src_buffer[offset_x]
+		[dst_blk_y + offset_y + y_crop_blocks];
 	      for (i = 0; i < DCTSIZE; i++)
 		for (j = 0; j < DCTSIZE; j++)
 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -292,6 +464,7 @@
 
 LOCAL(void)
 do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	    jvirt_barray_ptr *src_coef_arrays,
 	    jvirt_barray_ptr *dst_coef_arrays)
 /* 270 degree rotation is equivalent to
@@ -301,6 +474,7 @@
  */
 {
   JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_x, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JCOEFPTR src_ptr, dst_ptr;
@@ -310,11 +484,14 @@
    * at the (output) bottom edge properly.  They just get transposed and
    * not mirrored.
    */
-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+  MCU_rows = srcinfo->output_width /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
@@ -324,14 +501,15 @@
 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
 	     dst_blk_x += compptr->h_samp_factor) {
 	  src_buffer = (*srcinfo->mem->access_virt_barray)
-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
+	    ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	     dst_blk_x + x_crop_blocks,
 	     (JDIMENSION) compptr->h_samp_factor, FALSE);
 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
 	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
-	    if (dst_blk_y < comp_height) {
+	    if (y_crop_blocks + dst_blk_y < comp_height) {
 	      /* Block is within the mirrorable area. */
 	      src_ptr = src_buffer[offset_x]
-		[comp_height - dst_blk_y - offset_y - 1];
+		[comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
 	      for (i = 0; i < DCTSIZE; i++) {
 		for (j = 0; j < DCTSIZE; j++) {
 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -341,7 +519,8 @@
 	      }
 	    } else {
 	      /* Edge blocks are transposed but not mirrored. */
-	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
+	      src_ptr = src_buffer[offset_x]
+		[dst_blk_y + offset_y + y_crop_blocks];
 	      for (i = 0; i < DCTSIZE; i++)
 		for (j = 0; j < DCTSIZE; j++)
 		  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -356,6 +535,7 @@
 
 LOCAL(void)
 do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	    jvirt_barray_ptr *src_coef_arrays,
 	    jvirt_barray_ptr *dst_coef_arrays)
 /* 180 degree rotation is equivalent to
@@ -365,89 +545,95 @@
  */
 {
   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JBLOCKROW src_row_ptr, dst_row_ptr;
   JCOEFPTR src_ptr, dst_ptr;
   jpeg_component_info *compptr;
 
-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+  MCU_cols = srcinfo->output_width /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+  MCU_rows = srcinfo->output_height /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_width = MCU_cols * compptr->h_samp_factor;
     comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
 	((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
 	 (JDIMENSION) compptr->v_samp_factor, TRUE);
-      if (dst_blk_y < comp_height) {
+      if (y_crop_blocks + dst_blk_y < comp_height) {
 	/* Row is within the vertically mirrorable area. */
 	src_buffer = (*srcinfo->mem->access_virt_barray)
 	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
-	   comp_height - dst_blk_y - (JDIMENSION) compptr->v_samp_factor,
+	   comp_height - y_crop_blocks - dst_blk_y -
+	   (JDIMENSION) compptr->v_samp_factor,
 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
       } else {
 	/* Bottom-edge rows are only mirrored horizontally. */
 	src_buffer = (*srcinfo->mem->access_virt_barray)
-	  ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y,
+	  ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	   dst_blk_y + y_crop_blocks,
 	   (JDIMENSION) compptr->v_samp_factor, FALSE);
       }
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
-	if (dst_blk_y < comp_height) {
+	dst_row_ptr = dst_buffer[offset_y];
+	if (y_crop_blocks + dst_blk_y < comp_height) {
 	  /* Row is within the mirrorable area. */
-	  dst_row_ptr = dst_buffer[offset_y];
 	  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
-	  /* Process the blocks that can be mirrored both ways. */
-	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
+	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
 	    dst_ptr = dst_row_ptr[dst_blk_x];
-	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
-	    for (i = 0; i < DCTSIZE; i += 2) {
-	      /* For even row, negate every odd column. */
-	      for (j = 0; j < DCTSIZE; j += 2) {
-		*dst_ptr++ = *src_ptr++;
-		*dst_ptr++ = - *src_ptr++;
+	    if (x_crop_blocks + dst_blk_x < comp_width) {
+	      /* Process the blocks that can be mirrored both ways. */
+	      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+	      for (i = 0; i < DCTSIZE; i += 2) {
+		/* For even row, negate every odd column. */
+		for (j = 0; j < DCTSIZE; j += 2) {
+		  *dst_ptr++ = *src_ptr++;
+		  *dst_ptr++ = - *src_ptr++;
+		}
+		/* For odd row, negate every even column. */
+		for (j = 0; j < DCTSIZE; j += 2) {
+		  *dst_ptr++ = - *src_ptr++;
+		  *dst_ptr++ = *src_ptr++;
+		}
 	      }
-	      /* For odd row, negate every even column. */
-	      for (j = 0; j < DCTSIZE; j += 2) {
-		*dst_ptr++ = - *src_ptr++;
-		*dst_ptr++ = *src_ptr++;
+	    } else {
+	      /* Any remaining right-edge blocks are only mirrored vertically. */
+	      src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
+	      for (i = 0; i < DCTSIZE; i += 2) {
+		for (j = 0; j < DCTSIZE; j++)
+		  *dst_ptr++ = *src_ptr++;
+		for (j = 0; j < DCTSIZE; j++)
+		  *dst_ptr++ = - *src_ptr++;
 	      }
 	    }
 	  }
-	  /* Any remaining right-edge blocks are only mirrored vertically. */
-	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
-	    dst_ptr = dst_row_ptr[dst_blk_x];
-	    src_ptr = src_row_ptr[dst_blk_x];
-	    for (i = 0; i < DCTSIZE; i += 2) {
-	      for (j = 0; j < DCTSIZE; j++)
-		*dst_ptr++ = *src_ptr++;
-	      for (j = 0; j < DCTSIZE; j++)
-		*dst_ptr++ = - *src_ptr++;
-	    }
-	  }
 	} else {
 	  /* Remaining rows are just mirrored horizontally. */
-	  dst_row_ptr = dst_buffer[offset_y];
 	  src_row_ptr = src_buffer[offset_y];
-	  /* Process the blocks that can be mirrored. */
-	  for (dst_blk_x = 0; dst_blk_x < comp_width; dst_blk_x++) {
-	    dst_ptr = dst_row_ptr[dst_blk_x];
-	    src_ptr = src_row_ptr[comp_width - dst_blk_x - 1];
-	    for (i = 0; i < DCTSIZE2; i += 2) {
-	      *dst_ptr++ = *src_ptr++;
-	      *dst_ptr++ = - *src_ptr++;
+	  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+	    if (x_crop_blocks + dst_blk_x < comp_width) {
+	      /* Process the blocks that can be mirrored. */
+	      dst_ptr = dst_row_ptr[dst_blk_x];
+	      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+	      for (i = 0; i < DCTSIZE2; i += 2) {
+		*dst_ptr++ = *src_ptr++;
+		*dst_ptr++ = - *src_ptr++;
+	      }
+	    } else {
+	      /* Any remaining right-edge blocks are only copied. */
+	      jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+			      dst_row_ptr + dst_blk_x,
+			      (JDIMENSION) 1);
 	    }
 	  }
-	  /* Any remaining right-edge blocks are only copied. */
-	  for (; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
-	    dst_ptr = dst_row_ptr[dst_blk_x];
-	    src_ptr = src_row_ptr[dst_blk_x];
-	    for (i = 0; i < DCTSIZE2; i++)
-	      *dst_ptr++ = *src_ptr++;
-	  }
 	}
       }
     }
@@ -457,6 +643,7 @@
 
 LOCAL(void)
 do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+	       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
 	       jvirt_barray_ptr *src_coef_arrays,
 	       jvirt_barray_ptr *dst_coef_arrays)
 /* Transverse transpose is equivalent to
@@ -470,18 +657,23 @@
  */
 {
   JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+  JDIMENSION x_crop_blocks, y_crop_blocks;
   int ci, i, j, offset_x, offset_y;
   JBLOCKARRAY src_buffer, dst_buffer;
   JCOEFPTR src_ptr, dst_ptr;
   jpeg_component_info *compptr;
 
-  MCU_cols = dstinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE);
-  MCU_rows = dstinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE);
+  MCU_cols = srcinfo->output_height /
+    (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
+  MCU_rows = srcinfo->output_width /
+    (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
 
   for (ci = 0; ci < dstinfo->num_components; ci++) {
     compptr = dstinfo->comp_info + ci;
     comp_width = MCU_cols * compptr->h_samp_factor;
     comp_height = MCU_rows * compptr->v_samp_factor;
+    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
     for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
 	 dst_blk_y += compptr->v_samp_factor) {
       dst_buffer = (*srcinfo->mem->access_virt_barray)
@@ -490,17 +682,26 @@
       for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
 	for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
 	     dst_blk_x += compptr->h_samp_factor) {
-	  src_buffer = (*srcinfo->mem->access_virt_barray)
-	    ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x,
-	     (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  if (x_crop_blocks + dst_blk_x < comp_width) {
+	    /* Block is within the mirrorable area. */
+	    src_buffer = (*srcinfo->mem->access_virt_barray)
+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	       comp_width - x_crop_blocks - dst_blk_x -
+	       (JDIMENSION) compptr->h_samp_factor,
+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  } else {
+	    src_buffer = (*srcinfo->mem->access_virt_barray)
+	      ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+	       dst_blk_x + x_crop_blocks,
+	       (JDIMENSION) compptr->h_samp_factor, FALSE);
+	  }
 	  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
-	    if (dst_blk_y < comp_height) {
-	      src_ptr = src_buffer[offset_x]
-		[comp_height - dst_blk_y - offset_y - 1];
-	      if (dst_blk_x < comp_width) {
+	    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+	    if (y_crop_blocks + dst_blk_y < comp_height) {
+	      if (x_crop_blocks + dst_blk_x < comp_width) {
 		/* Block is within the mirrorable area. */
-		dst_ptr = dst_buffer[offset_y]
-		  [comp_width - dst_blk_x - offset_x - 1];
+		src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+		  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
 		for (i = 0; i < DCTSIZE; i++) {
 		  for (j = 0; j < DCTSIZE; j++) {
 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -516,7 +717,8 @@
 		}
 	      } else {
 		/* Right-edge blocks are mirrored in y only */
-		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+		src_ptr = src_buffer[offset_x]
+		  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
 		for (i = 0; i < DCTSIZE; i++) {
 		  for (j = 0; j < DCTSIZE; j++) {
 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -526,11 +728,10 @@
 		}
 	      }
 	    } else {
-	      src_ptr = src_buffer[offset_x][dst_blk_y + offset_y];
-	      if (dst_blk_x < comp_width) {
+	      if (x_crop_blocks + dst_blk_x < comp_width) {
 		/* Bottom-edge blocks are mirrored in x only */
-		dst_ptr = dst_buffer[offset_y]
-		  [comp_width - dst_blk_x - offset_x - 1];
+		src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+		  [dst_blk_y + offset_y + y_crop_blocks];
 		for (i = 0; i < DCTSIZE; i++) {
 		  for (j = 0; j < DCTSIZE; j++)
 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -540,7 +741,8 @@
 		}
 	      } else {
 		/* At lower right corner, just transpose, no mirroring */
-		dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+		src_ptr = src_buffer[offset_x]
+		  [dst_blk_y + offset_y + y_crop_blocks];
 		for (i = 0; i < DCTSIZE; i++)
 		  for (j = 0; j < DCTSIZE; j++)
 		    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
@@ -554,83 +756,358 @@
 }
 
 
+/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
+ * Returns TRUE if valid integer found, FALSE if not.
+ * *strptr is advanced over the digit string, and *result is set to its value.
+ */
+
+LOCAL(boolean)
+jt_read_integer (const char ** strptr, JDIMENSION * result)
+{
+  const char * ptr = *strptr;
+  JDIMENSION val = 0;
+
+  for (; isdigit(*ptr); ptr++) {
+    val = val * 10 + (JDIMENSION) (*ptr - '0');
+  }
+  *result = val;
+  if (ptr == *strptr)
+    return FALSE;		/* oops, no digits */
+  *strptr = ptr;
+  return TRUE;
+}
+
+
+/* Parse a crop specification (written in X11 geometry style).
+ * The routine returns TRUE if the spec string is valid, FALSE if not.
+ *
+ * The crop spec string should have the format
+ *	<width>x<height>{+-}<xoffset>{+-}<yoffset>
+ * where width, height, xoffset, and yoffset are unsigned integers.
+ * Each of the elements can be omitted to indicate a default value.
+ * (A weakness of this style is that it is not possible to omit xoffset
+ * while specifying yoffset, since they look alike.)
+ *
+ * This code is loosely based on XParseGeometry from the X11 distribution.
+ */
+
+GLOBAL(boolean)
+jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
+{
+  info->crop = FALSE;
+  info->crop_width_set = JCROP_UNSET;
+  info->crop_height_set = JCROP_UNSET;
+  info->crop_xoffset_set = JCROP_UNSET;
+  info->crop_yoffset_set = JCROP_UNSET;
+
+  if (isdigit(*spec)) {
+    /* fetch width */
+    if (! jt_read_integer(&spec, &info->crop_width))
+      return FALSE;
+    info->crop_width_set = JCROP_POS;
+  }
+  if (*spec == 'x' || *spec == 'X') {	
+    /* fetch height */
+    spec++;
+    if (! jt_read_integer(&spec, &info->crop_height))
+      return FALSE;
+    info->crop_height_set = JCROP_POS;
+  }
+  if (*spec == '+' || *spec == '-') {
+    /* fetch xoffset */
+    info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
+    spec++;
+    if (! jt_read_integer(&spec, &info->crop_xoffset))
+      return FALSE;
+  }
+  if (*spec == '+' || *spec == '-') {
+    /* fetch yoffset */
+    info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
+    spec++;
+    if (! jt_read_integer(&spec, &info->crop_yoffset))
+      return FALSE;
+  }
+  /* We had better have gotten to the end of the string. */
+  if (*spec != '\0')
+    return FALSE;
+  info->crop = TRUE;
+  return TRUE;
+}
+
+
+/* Trim off any partial iMCUs on the indicated destination edge */
+
+LOCAL(void)
+trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
+{
+  JDIMENSION MCU_cols;
+
+  MCU_cols = info->output_width / info->iMCU_sample_width;
+  if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
+      full_width / info->iMCU_sample_width)
+    info->output_width = MCU_cols * info->iMCU_sample_width;
+}
+
+LOCAL(void)
+trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
+{
+  JDIMENSION MCU_rows;
+
+  MCU_rows = info->output_height / info->iMCU_sample_height;
+  if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
+      full_height / info->iMCU_sample_height)
+    info->output_height = MCU_rows * info->iMCU_sample_height;
+}
+
+
 /* Request any required workspace.
  *
+ * This routine figures out the size that the output image will be
+ * (which implies that all the transform parameters must be set before
+ * it is called).
+ *
  * We allocate the workspace virtual arrays from the source decompression
  * object, so that all the arrays (both the original data and the workspace)
  * will be taken into account while making memory management decisions.
  * Hence, this routine must be called after jpeg_read_header (which reads
  * the image dimensions) and before jpeg_read_coefficients (which realizes
  * the source's virtual arrays).
+ *
+ * This function returns FALSE right away if -perfect is given
+ * and transformation is not perfect.  Otherwise returns TRUE.
  */
 
-GLOBAL(void)
+GLOBAL(boolean)
 jtransform_request_workspace (j_decompress_ptr srcinfo,
 			      jpeg_transform_info *info)
 {
-  jvirt_barray_ptr *coef_arrays = NULL;
+  jvirt_barray_ptr *coef_arrays;
+  boolean need_workspace, transpose_it;
   jpeg_component_info *compptr;
-  int ci;
+  JDIMENSION xoffset, yoffset;
+  JDIMENSION width_in_iMCUs, height_in_iMCUs;
+  JDIMENSION width_in_blocks, height_in_blocks;
+  int ci, h_samp_factor, v_samp_factor;
 
+  /* Determine number of components in output image */
   if (info->force_grayscale &&
       srcinfo->jpeg_color_space == JCS_YCbCr &&
-      srcinfo->num_components == 3) {
+      srcinfo->num_components == 3)
     /* We'll only process the first component */
     info->num_components = 1;
-  } else {
+  else
     /* Process all the components */
     info->num_components = srcinfo->num_components;
+
+  /* Compute output image dimensions and related values. */
+#if JPEG_LIB_VERSION >= 80
+  jpeg_core_output_dimensions(srcinfo);
+#else
+  srcinfo->output_width = srcinfo->image_width;
+  srcinfo->output_height = srcinfo->image_height;
+#endif
+
+  /* Return right away if -perfect is given and transformation is not perfect.
+   */
+  if (info->perfect) {
+    if (info->num_components == 1) {
+      if (!jtransform_perfect_transform(srcinfo->output_width,
+	  srcinfo->output_height,
+	  srcinfo->_min_DCT_h_scaled_size,
+	  srcinfo->_min_DCT_v_scaled_size,
+	  info->transform))
+	return FALSE;
+    } else {
+      if (!jtransform_perfect_transform(srcinfo->output_width,
+	  srcinfo->output_height,
+	  srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
+	  srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
+	  info->transform))
+	return FALSE;
+    }
   }
 
+  /* If there is only one output component, force the iMCU size to be 1;
+   * else use the source iMCU size.  (This allows us to do the right thing
+   * when reducing color to grayscale, and also provides a handy way of
+   * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
+   */
   switch (info->transform) {
-  case JXFORM_NONE:
-  case JXFORM_FLIP_H:
-    /* Don't need a workspace array */
-    break;
-  case JXFORM_FLIP_V:
-  case JXFORM_ROT_180:
-    /* Need workspace arrays having same dimensions as source image.
-     * Note that we allocate arrays padded out to the next iMCU boundary,
-     * so that transform routines need not worry about missing edge blocks.
-     */
-    coef_arrays = (jvirt_barray_ptr *)
-      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
-	SIZEOF(jvirt_barray_ptr) * info->num_components);
-    for (ci = 0; ci < info->num_components; ci++) {
-      compptr = srcinfo->comp_info + ci;
-      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
-	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
-	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
-				(long) compptr->h_samp_factor),
-	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
-				(long) compptr->v_samp_factor),
-	 (JDIMENSION) compptr->v_samp_factor);
-    }
-    break;
   case JXFORM_TRANSPOSE:
   case JXFORM_TRANSVERSE:
   case JXFORM_ROT_90:
   case JXFORM_ROT_270:
-    /* Need workspace arrays having transposed dimensions.
-     * Note that we allocate arrays padded out to the next iMCU boundary,
-     * so that transform routines need not worry about missing edge blocks.
-     */
-    coef_arrays = (jvirt_barray_ptr *)
-      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
-	SIZEOF(jvirt_barray_ptr) * info->num_components);
-    for (ci = 0; ci < info->num_components; ci++) {
-      compptr = srcinfo->comp_info + ci;
-      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
-	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
-	 (JDIMENSION) jround_up((long) compptr->height_in_blocks,
-				(long) compptr->v_samp_factor),
-	 (JDIMENSION) jround_up((long) compptr->width_in_blocks,
-				(long) compptr->h_samp_factor),
-	 (JDIMENSION) compptr->h_samp_factor);
+    info->output_width = srcinfo->output_height;
+    info->output_height = srcinfo->output_width;
+    if (info->num_components == 1) {
+      info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
+      info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
+    } else {
+      info->iMCU_sample_width =
+	srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
+      info->iMCU_sample_height =
+	srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
+    }
+    break;
+  default:
+    info->output_width = srcinfo->output_width;
+    info->output_height = srcinfo->output_height;
+    if (info->num_components == 1) {
+      info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
+      info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
+    } else {
+      info->iMCU_sample_width =
+	srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
+      info->iMCU_sample_height =
+	srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
     }
     break;
   }
-  info->workspace_coef_arrays = coef_arrays;
+
+  /* If cropping has been requested, compute the crop area's position and
+   * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
+   */
+  if (info->crop) {
+    /* Insert default values for unset crop parameters */
+    if (info->crop_xoffset_set == JCROP_UNSET)
+      info->crop_xoffset = 0;	/* default to +0 */
+    if (info->crop_yoffset_set == JCROP_UNSET)
+      info->crop_yoffset = 0;	/* default to +0 */
+    if (info->crop_xoffset >= info->output_width ||
+	info->crop_yoffset >= info->output_height)
+      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+    if (info->crop_width_set == JCROP_UNSET)
+      info->crop_width = info->output_width - info->crop_xoffset;
+    if (info->crop_height_set == JCROP_UNSET)
+      info->crop_height = info->output_height - info->crop_yoffset;
+    /* Ensure parameters are valid */
+    if (info->crop_width <= 0 || info->crop_width > info->output_width ||
+	info->crop_height <= 0 || info->crop_height > info->output_height ||
+	info->crop_xoffset > info->output_width - info->crop_width ||
+	info->crop_yoffset > info->output_height - info->crop_height)
+      ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+    /* Convert negative crop offsets into regular offsets */
+    if (info->crop_xoffset_set == JCROP_NEG)
+      xoffset = info->output_width - info->crop_width - info->crop_xoffset;
+    else
+      xoffset = info->crop_xoffset;
+    if (info->crop_yoffset_set == JCROP_NEG)
+      yoffset = info->output_height - info->crop_height - info->crop_yoffset;
+    else
+      yoffset = info->crop_yoffset;
+    /* Now adjust so that upper left corner falls at an iMCU boundary */
+    info->output_width =
+      info->crop_width + (xoffset % info->iMCU_sample_width);
+    info->output_height =
+      info->crop_height + (yoffset % info->iMCU_sample_height);
+    /* Save x/y offsets measured in iMCUs */
+    info->x_crop_offset = xoffset / info->iMCU_sample_width;
+    info->y_crop_offset = yoffset / info->iMCU_sample_height;
+  } else {
+    info->x_crop_offset = 0;
+    info->y_crop_offset = 0;
+  }
+
+  /* Figure out whether we need workspace arrays,
+   * and if so whether they are transposed relative to the source.
+   */
+  need_workspace = FALSE;
+  transpose_it = FALSE;
+  switch (info->transform) {
+  case JXFORM_NONE:
+    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+      need_workspace = TRUE;
+    /* No workspace needed if neither cropping nor transforming */
+    break;
+  case JXFORM_FLIP_H:
+    if (info->trim)
+      trim_right_edge(info, srcinfo->output_width);
+    if (info->y_crop_offset != 0)
+      need_workspace = TRUE;
+    /* do_flip_h_no_crop doesn't need a workspace array */
+    break;
+  case JXFORM_FLIP_V:
+    if (info->trim)
+      trim_bottom_edge(info, srcinfo->output_height);
+    /* Need workspace arrays having same dimensions as source image. */
+    need_workspace = TRUE;
+    break;
+  case JXFORM_TRANSPOSE:
+    /* transpose does NOT have to trim anything */
+    /* Need workspace arrays having transposed dimensions. */
+    need_workspace = TRUE;
+    transpose_it = TRUE;
+    break;
+  case JXFORM_TRANSVERSE:
+    if (info->trim) {
+      trim_right_edge(info, srcinfo->output_height);
+      trim_bottom_edge(info, srcinfo->output_width);
+    }
+    /* Need workspace arrays having transposed dimensions. */
+    need_workspace = TRUE;
+    transpose_it = TRUE;
+    break;
+  case JXFORM_ROT_90:
+    if (info->trim)
+      trim_right_edge(info, srcinfo->output_height);
+    /* Need workspace arrays having transposed dimensions. */
+    need_workspace = TRUE;
+    transpose_it = TRUE;
+    break;
+  case JXFORM_ROT_180:
+    if (info->trim) {
+      trim_right_edge(info, srcinfo->output_width);
+      trim_bottom_edge(info, srcinfo->output_height);
+    }
+    /* Need workspace arrays having same dimensions as source image. */
+    need_workspace = TRUE;
+    break;
+  case JXFORM_ROT_270:
+    if (info->trim)
+      trim_bottom_edge(info, srcinfo->output_width);
+    /* Need workspace arrays having transposed dimensions. */
+    need_workspace = TRUE;
+    transpose_it = TRUE;
+    break;
+  }
+
+  /* Allocate workspace if needed.
+   * Note that we allocate arrays padded out to the next iMCU boundary,
+   * so that transform routines need not worry about missing edge blocks.
+   */
+  if (need_workspace) {
+    coef_arrays = (jvirt_barray_ptr *)
+      (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
+		SIZEOF(jvirt_barray_ptr) * info->num_components);
+    width_in_iMCUs = (JDIMENSION)
+      jdiv_round_up((long) info->output_width,
+		    (long) info->iMCU_sample_width);
+    height_in_iMCUs = (JDIMENSION)
+      jdiv_round_up((long) info->output_height,
+		    (long) info->iMCU_sample_height);
+    for (ci = 0; ci < info->num_components; ci++) {
+      compptr = srcinfo->comp_info + ci;
+      if (info->num_components == 1) {
+	/* we're going to force samp factors to 1x1 in this case */
+	h_samp_factor = v_samp_factor = 1;
+      } else if (transpose_it) {
+	h_samp_factor = compptr->v_samp_factor;
+	v_samp_factor = compptr->h_samp_factor;
+      } else {
+	h_samp_factor = compptr->h_samp_factor;
+	v_samp_factor = compptr->v_samp_factor;
+      }
+      width_in_blocks = width_in_iMCUs * h_samp_factor;
+      height_in_blocks = height_in_iMCUs * v_samp_factor;
+      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
+	((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
+	 width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
+    }
+    info->workspace_coef_arrays = coef_arrays;
+  } else
+    info->workspace_coef_arrays = NULL;
+
+  return TRUE;
 }
 
 
@@ -642,13 +1119,18 @@
   int tblno, i, j, ci, itemp;
   jpeg_component_info *compptr;
   JQUANT_TBL *qtblptr;
-  JDIMENSION dtemp;
+  JDIMENSION jtemp;
   UINT16 qtemp;
 
-  /* Transpose basic image dimensions */
-  dtemp = dstinfo->image_width;
+  /* Transpose image dimensions */
+  jtemp = dstinfo->image_width;
   dstinfo->image_width = dstinfo->image_height;
-  dstinfo->image_height = dtemp;
+  dstinfo->image_height = jtemp;
+#if JPEG_LIB_VERSION >= 70
+  itemp = dstinfo->min_DCT_h_scaled_size;
+  dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
+  dstinfo->min_DCT_v_scaled_size = itemp;
+#endif
 
   /* Transpose sampling factors */
   for (ci = 0; ci < dstinfo->num_components; ci++) {
@@ -674,46 +1156,159 @@
 }
 
 
-/* Trim off any partial iMCUs on the indicated destination edge */
+/* Adjust Exif image parameters.
+ *
+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
+ */
 
 LOCAL(void)
-trim_right_edge (j_compress_ptr dstinfo)
+adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
+			JDIMENSION new_width, JDIMENSION new_height)
 {
-  int ci, max_h_samp_factor;
-  JDIMENSION MCU_cols;
+  boolean is_motorola; /* Flag for byte order */
+  unsigned int number_of_tags, tagnum;
+  unsigned int firstoffset, offset;
+  JDIMENSION new_value;
 
-  /* We have to compute max_h_samp_factor ourselves,
-   * because it hasn't been set yet in the destination
-   * (and we don't want to use the source's value).
-   */
-  max_h_samp_factor = 1;
-  for (ci = 0; ci < dstinfo->num_components; ci++) {
-    int h_samp_factor = dstinfo->comp_info[ci].h_samp_factor;
-    max_h_samp_factor = MAX(max_h_samp_factor, h_samp_factor);
+  if (length < 12) return; /* Length of an IFD entry */
+
+  /* Discover byte order */
+  if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
+    is_motorola = FALSE;
+  else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
+    is_motorola = TRUE;
+  else
+    return;
+
+  /* Check Tag Mark */
+  if (is_motorola) {
+    if (GETJOCTET(data[2]) != 0) return;
+    if (GETJOCTET(data[3]) != 0x2A) return;
+  } else {
+    if (GETJOCTET(data[3]) != 0) return;
+    if (GETJOCTET(data[2]) != 0x2A) return;
   }
-  MCU_cols = dstinfo->image_width / (max_h_samp_factor * DCTSIZE);
-  if (MCU_cols > 0)		/* can't trim to 0 pixels */
-    dstinfo->image_width = MCU_cols * (max_h_samp_factor * DCTSIZE);
-}
 
-LOCAL(void)
-trim_bottom_edge (j_compress_ptr dstinfo)
-{
-  int ci, max_v_samp_factor;
-  JDIMENSION MCU_rows;
-
-  /* We have to compute max_v_samp_factor ourselves,
-   * because it hasn't been set yet in the destination
-   * (and we don't want to use the source's value).
-   */
-  max_v_samp_factor = 1;
-  for (ci = 0; ci < dstinfo->num_components; ci++) {
-    int v_samp_factor = dstinfo->comp_info[ci].v_samp_factor;
-    max_v_samp_factor = MAX(max_v_samp_factor, v_samp_factor);
+  /* Get first IFD offset (offset to IFD0) */
+  if (is_motorola) {
+    if (GETJOCTET(data[4]) != 0) return;
+    if (GETJOCTET(data[5]) != 0) return;
+    firstoffset = GETJOCTET(data[6]);
+    firstoffset <<= 8;
+    firstoffset += GETJOCTET(data[7]);
+  } else {
+    if (GETJOCTET(data[7]) != 0) return;
+    if (GETJOCTET(data[6]) != 0) return;
+    firstoffset = GETJOCTET(data[5]);
+    firstoffset <<= 8;
+    firstoffset += GETJOCTET(data[4]);
   }
-  MCU_rows = dstinfo->image_height / (max_v_samp_factor * DCTSIZE);
-  if (MCU_rows > 0)		/* can't trim to 0 pixels */
-    dstinfo->image_height = MCU_rows * (max_v_samp_factor * DCTSIZE);
+  if (firstoffset > length - 2) return; /* check end of data segment */
+
+  /* Get the number of directory entries contained in this IFD */
+  if (is_motorola) {
+    number_of_tags = GETJOCTET(data[firstoffset]);
+    number_of_tags <<= 8;
+    number_of_tags += GETJOCTET(data[firstoffset+1]);
+  } else {
+    number_of_tags = GETJOCTET(data[firstoffset+1]);
+    number_of_tags <<= 8;
+    number_of_tags += GETJOCTET(data[firstoffset]);
+  }
+  if (number_of_tags == 0) return;
+  firstoffset += 2;
+
+  /* Search for ExifSubIFD offset Tag in IFD0 */
+  for (;;) {
+    if (firstoffset > length - 12) return; /* check end of data segment */
+    /* Get Tag number */
+    if (is_motorola) {
+      tagnum = GETJOCTET(data[firstoffset]);
+      tagnum <<= 8;
+      tagnum += GETJOCTET(data[firstoffset+1]);
+    } else {
+      tagnum = GETJOCTET(data[firstoffset+1]);
+      tagnum <<= 8;
+      tagnum += GETJOCTET(data[firstoffset]);
+    }
+    if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
+    if (--number_of_tags == 0) return;
+    firstoffset += 12;
+  }
+
+  /* Get the ExifSubIFD offset */
+  if (is_motorola) {
+    if (GETJOCTET(data[firstoffset+8]) != 0) return;
+    if (GETJOCTET(data[firstoffset+9]) != 0) return;
+    offset = GETJOCTET(data[firstoffset+10]);
+    offset <<= 8;
+    offset += GETJOCTET(data[firstoffset+11]);
+  } else {
+    if (GETJOCTET(data[firstoffset+11]) != 0) return;
+    if (GETJOCTET(data[firstoffset+10]) != 0) return;
+    offset = GETJOCTET(data[firstoffset+9]);
+    offset <<= 8;
+    offset += GETJOCTET(data[firstoffset+8]);
+  }
+  if (offset > length - 2) return; /* check end of data segment */
+
+  /* Get the number of directory entries contained in this SubIFD */
+  if (is_motorola) {
+    number_of_tags = GETJOCTET(data[offset]);
+    number_of_tags <<= 8;
+    number_of_tags += GETJOCTET(data[offset+1]);
+  } else {
+    number_of_tags = GETJOCTET(data[offset+1]);
+    number_of_tags <<= 8;
+    number_of_tags += GETJOCTET(data[offset]);
+  }
+  if (number_of_tags < 2) return;
+  offset += 2;
+
+  /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
+  do {
+    if (offset > length - 12) return; /* check end of data segment */
+    /* Get Tag number */
+    if (is_motorola) {
+      tagnum = GETJOCTET(data[offset]);
+      tagnum <<= 8;
+      tagnum += GETJOCTET(data[offset+1]);
+    } else {
+      tagnum = GETJOCTET(data[offset+1]);
+      tagnum <<= 8;
+      tagnum += GETJOCTET(data[offset]);
+    }
+    if (tagnum == 0xA002 || tagnum == 0xA003) {
+      if (tagnum == 0xA002)
+	new_value = new_width; /* ExifImageWidth Tag */
+      else
+	new_value = new_height; /* ExifImageHeight Tag */
+      if (is_motorola) {
+	data[offset+2] = 0; /* Format = unsigned long (4 octets) */
+	data[offset+3] = 4;
+	data[offset+4] = 0; /* Number Of Components = 1 */
+	data[offset+5] = 0;
+	data[offset+6] = 0;
+	data[offset+7] = 1;
+	data[offset+8] = 0;
+	data[offset+9] = 0;
+	data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
+	data[offset+11] = (JOCTET)(new_value & 0xFF);
+      } else {
+	data[offset+2] = 4; /* Format = unsigned long (4 octets) */
+	data[offset+3] = 0;
+	data[offset+4] = 1; /* Number Of Components = 1 */
+	data[offset+5] = 0;
+	data[offset+6] = 0;
+	data[offset+7] = 0;
+	data[offset+8] = (JOCTET)(new_value & 0xFF);
+	data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
+	data[offset+10] = 0;
+	data[offset+11] = 0;
+      }
+    }
+    offset += 12;
+  } while (--number_of_tags);
 }
 
 
@@ -736,18 +1331,22 @@
 {
   /* If force-to-grayscale is requested, adjust destination parameters */
   if (info->force_grayscale) {
-    /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
-     * properly.  Among other things, the target h_samp_factor & v_samp_factor
-     * will get set to 1, which typically won't match the source.
-     * In fact we do this even if the source is already grayscale; that
-     * provides an easy way of coercing a grayscale JPEG with funny sampling
-     * factors to the customary 1,1.  (Some decoders fail on other factors.)
+    /* First, ensure we have YCbCr or grayscale data, and that the source's
+     * Y channel is full resolution.  (No reasonable person would make Y
+     * be less than full resolution, so actually coping with that case
+     * isn't worth extra code space.  But we check it to avoid crashing.)
      */
-    if ((dstinfo->jpeg_color_space == JCS_YCbCr &&
-	 dstinfo->num_components == 3) ||
-	(dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
-	 dstinfo->num_components == 1)) {
-      /* We have to preserve the source's quantization table number. */
+    if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
+	  dstinfo->num_components == 3) ||
+	 (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
+	  dstinfo->num_components == 1)) &&
+	srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
+	srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
+      /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
+       * properly.  Among other things, it sets the target h_samp_factor &
+       * v_samp_factor to 1, which typically won't match the source.
+       * We have to preserve the source's quantization table number, however.
+       */
       int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
       jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
       dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
@@ -755,48 +1354,64 @@
       /* Sorry, can't do it */
       ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
     }
+  } else if (info->num_components == 1) {
+    /* For a single-component source, we force the destination sampling factors
+     * to 1x1, with or without force_grayscale.  This is useful because some
+     * decoders choke on grayscale images with other sampling factors.
+     */
+    dstinfo->comp_info[0].h_samp_factor = 1;
+    dstinfo->comp_info[0].v_samp_factor = 1;
   }
 
-  /* Correct the destination's image dimensions etc if necessary */
+  /* Correct the destination's image dimensions as necessary
+   * for rotate/flip, resize, and crop operations.
+   */
+#if JPEG_LIB_VERSION >= 70
+  dstinfo->jpeg_width = info->output_width;
+  dstinfo->jpeg_height = info->output_height;
+#endif
+
+  /* Transpose destination image parameters */
   switch (info->transform) {
-  case JXFORM_NONE:
-    /* Nothing to do */
-    break;
-  case JXFORM_FLIP_H:
-    if (info->trim)
-      trim_right_edge(dstinfo);
-    break;
-  case JXFORM_FLIP_V:
-    if (info->trim)
-      trim_bottom_edge(dstinfo);
-    break;
   case JXFORM_TRANSPOSE:
-    transpose_critical_parameters(dstinfo);
-    /* transpose does NOT have to trim anything */
-    break;
   case JXFORM_TRANSVERSE:
-    transpose_critical_parameters(dstinfo);
-    if (info->trim) {
-      trim_right_edge(dstinfo);
-      trim_bottom_edge(dstinfo);
-    }
-    break;
   case JXFORM_ROT_90:
-    transpose_critical_parameters(dstinfo);
-    if (info->trim)
-      trim_right_edge(dstinfo);
-    break;
-  case JXFORM_ROT_180:
-    if (info->trim) {
-      trim_right_edge(dstinfo);
-      trim_bottom_edge(dstinfo);
-    }
-    break;
   case JXFORM_ROT_270:
+#if JPEG_LIB_VERSION < 70
+    dstinfo->image_width = info->output_height;
+    dstinfo->image_height = info->output_width;
+#endif
     transpose_critical_parameters(dstinfo);
-    if (info->trim)
-      trim_bottom_edge(dstinfo);
     break;
+  default:
+#if JPEG_LIB_VERSION < 70
+    dstinfo->image_width = info->output_width;
+    dstinfo->image_height = info->output_height;
+#endif
+    break;
+  }
+
+  /* Adjust Exif properties */
+  if (srcinfo->marker_list != NULL &&
+      srcinfo->marker_list->marker == JPEG_APP0+1 &&
+      srcinfo->marker_list->data_length >= 6 &&
+      GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
+      GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
+      GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
+      GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
+      GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
+      GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
+    /* Suppress output of JFIF marker */
+    dstinfo->write_JFIF_header = FALSE;
+#if JPEG_LIB_VERSION >= 70
+    /* Adjust Exif image parameters */
+    if (dstinfo->jpeg_width != srcinfo->image_width ||
+	dstinfo->jpeg_height != srcinfo->image_height)
+      /* Align data segment to start of TIFF structure for parsing */
+      adjust_exif_parameters(srcinfo->marker_list->data + 6,
+	srcinfo->marker_list->data_length - 6,
+	dstinfo->jpeg_width, dstinfo->jpeg_height);
+#endif
   }
 
   /* Return the appropriate output data set */
@@ -816,40 +1431,110 @@
  */
 
 GLOBAL(void)
-jtransform_execute_transformation (j_decompress_ptr srcinfo,
-				   j_compress_ptr dstinfo,
-				   jvirt_barray_ptr *src_coef_arrays,
-				   jpeg_transform_info *info)
+jtransform_execute_transform (j_decompress_ptr srcinfo,
+			      j_compress_ptr dstinfo,
+			      jvirt_barray_ptr *src_coef_arrays,
+			      jpeg_transform_info *info)
 {
   jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
 
+  /* Note: conditions tested here should match those in switch statement
+   * in jtransform_request_workspace()
+   */
   switch (info->transform) {
   case JXFORM_NONE:
+    if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+      do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+	      src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_FLIP_H:
-    do_flip_h(srcinfo, dstinfo, src_coef_arrays);
+    if (info->y_crop_offset != 0)
+      do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+		src_coef_arrays, dst_coef_arrays);
+    else
+      do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
+			src_coef_arrays);
     break;
   case JXFORM_FLIP_V:
-    do_flip_v(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+	      src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_TRANSPOSE:
-    do_transpose(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+		 src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_TRANSVERSE:
-    do_transverse(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+		  src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_ROT_90:
-    do_rot_90(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+	      src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_ROT_180:
-    do_rot_180(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+	       src_coef_arrays, dst_coef_arrays);
     break;
   case JXFORM_ROT_270:
-    do_rot_270(srcinfo, dstinfo, src_coef_arrays, dst_coef_arrays);
+    do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+	       src_coef_arrays, dst_coef_arrays);
     break;
   }
 }
 
+/* jtransform_perfect_transform
+ *
+ * Determine whether lossless transformation is perfectly
+ * possible for a specified image and transformation.
+ *
+ * Inputs:
+ *   image_width, image_height: source image dimensions.
+ *   MCU_width, MCU_height: pixel dimensions of MCU.
+ *   transform: transformation identifier.
+ * Parameter sources from initialized jpeg_struct
+ * (after reading source header):
+ *   image_width = cinfo.image_width
+ *   image_height = cinfo.image_height
+ *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
+ *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
+ * Result:
+ *   TRUE = perfect transformation possible
+ *   FALSE = perfect transformation not possible
+ *           (may use custom action then)
+ */
+
+GLOBAL(boolean)
+jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
+			     int MCU_width, int MCU_height,
+			     JXFORM_CODE transform)
+{
+  boolean result = TRUE; /* initialize TRUE */
+
+  switch (transform) {
+  case JXFORM_FLIP_H:
+  case JXFORM_ROT_270:
+    if (image_width % (JDIMENSION) MCU_width)
+      result = FALSE;
+    break;
+  case JXFORM_FLIP_V:
+  case JXFORM_ROT_90:
+    if (image_height % (JDIMENSION) MCU_height)
+      result = FALSE;
+    break;
+  case JXFORM_TRANSVERSE:
+  case JXFORM_ROT_180:
+    if (image_width % (JDIMENSION) MCU_width)
+      result = FALSE;
+    if (image_height % (JDIMENSION) MCU_height)
+      result = FALSE;
+    break;
+  default:
+    break;
+  }
+
+  return result;
+}
+
 #endif /* TRANSFORMS_SUPPORTED */
 
 
diff --git a/transupp.h b/transupp.h
index 5c2d32a..7c16c19 100644
--- a/transupp.h
+++ b/transupp.h
@@ -1,7 +1,7 @@
 /*
  * transupp.h
  *
- * Copyright (C) 1997, Thomas G. Lane.
+ * Copyright (C) 1997-2009, Thomas G. Lane, Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -22,32 +22,6 @@
 #define TRANSFORMS_SUPPORTED 1		/* 0 disables transform code */
 #endif
 
-/* Short forms of external names for systems with brain-damaged linkers. */
-
-#ifdef NEED_SHORT_EXTERNAL_NAMES
-#define jtransform_request_workspace		jTrRequest
-#define jtransform_adjust_parameters		jTrAdjust
-#define jtransform_execute_transformation	jTrExec
-#define jcopy_markers_setup			jCMrkSetup
-#define jcopy_markers_execute			jCMrkExec
-#endif /* NEED_SHORT_EXTERNAL_NAMES */
-
-
-/*
- * Codes for supported types of image transformations.
- */
-
-typedef enum {
-	JXFORM_NONE,		/* no transformation */
-	JXFORM_FLIP_H,		/* horizontal flip */
-	JXFORM_FLIP_V,		/* vertical flip */
-	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
-	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
-	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
-	JXFORM_ROT_180,		/* 180-degree rotation */
-	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
-} JXFORM_CODE;
-
 /*
  * Although rotating and flipping data expressed as DCT coefficients is not
  * hard, there is an asymmetry in the JPEG format specification for images
@@ -75,6 +49,24 @@
  * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
  * followed by -rot 180 -trim trims both edges.)
  *
+ * We also offer a lossless-crop option, which discards data outside a given
+ * image region but losslessly preserves what is inside.  Like the rotate and
+ * flip transforms, lossless crop is restricted by the JPEG format: the upper
+ * left corner of the selected region must fall on an iMCU boundary.  If this
+ * does not hold for the given crop parameters, we silently move the upper left
+ * corner up and/or left to make it so, simultaneously increasing the region
+ * dimensions to keep the lower right crop corner unchanged.  (Thus, the
+ * output image covers at least the requested region, but may cover more.)
+ *
+ * We also provide a lossless-resize option, which is kind of a lossless-crop
+ * operation in the DCT coefficient block domain - it discards higher-order
+ * coefficients and losslessly preserves lower-order coefficients of a
+ * sub-block.
+ *
+ * Rotate/flip transform, resize, and crop can be requested together in a
+ * single invocation.  The crop is applied last --- that is, the crop region
+ * is specified in terms of the destination image after transform/resize.
+ *
  * We also offer a "force to grayscale" option, which simply discards the
  * chrominance channels of a YCbCr image.  This is lossless in the sense that
  * the luminance channel is preserved exactly.  It's not the same kind of
@@ -83,22 +75,91 @@
  * be aware of the option to know how many components to work on.
  */
 
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jtransform_parse_crop_spec	jTrParCrop
+#define jtransform_request_workspace	jTrRequest
+#define jtransform_adjust_parameters	jTrAdjust
+#define jtransform_execute_transform	jTrExec
+#define jtransform_perfect_transform	jTrPerfect
+#define jcopy_markers_setup		jCMrkSetup
+#define jcopy_markers_execute		jCMrkExec
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * Codes for supported types of image transformations.
+ */
+
+typedef enum {
+	JXFORM_NONE,		/* no transformation */
+	JXFORM_FLIP_H,		/* horizontal flip */
+	JXFORM_FLIP_V,		/* vertical flip */
+	JXFORM_TRANSPOSE,	/* transpose across UL-to-LR axis */
+	JXFORM_TRANSVERSE,	/* transpose across UR-to-LL axis */
+	JXFORM_ROT_90,		/* 90-degree clockwise rotation */
+	JXFORM_ROT_180,		/* 180-degree rotation */
+	JXFORM_ROT_270		/* 270-degree clockwise (or 90 ccw) */
+} JXFORM_CODE;
+
+/*
+ * Codes for crop parameters, which can individually be unspecified,
+ * positive, or negative.  (Negative width or height makes no sense, though.)
+ */
+
+typedef enum {
+	JCROP_UNSET,
+	JCROP_POS,
+	JCROP_NEG
+} JCROP_CODE;
+
+/*
+ * Transform parameters struct.
+ * NB: application must not change any elements of this struct after
+ * calling jtransform_request_workspace.
+ */
+
 typedef struct {
   /* Options: set by caller */
   JXFORM_CODE transform;	/* image transform operator */
+  boolean perfect;		/* if TRUE, fail if partial MCUs are requested */
   boolean trim;			/* if TRUE, trim partial MCUs as needed */
   boolean force_grayscale;	/* if TRUE, convert color image to grayscale */
+  boolean crop;			/* if TRUE, crop source image */
+
+  /* Crop parameters: application need not set these unless crop is TRUE.
+   * These can be filled in by jtransform_parse_crop_spec().
+   */
+  JDIMENSION crop_width;	/* Width of selected region */
+  JCROP_CODE crop_width_set;
+  JDIMENSION crop_height;	/* Height of selected region */
+  JCROP_CODE crop_height_set;
+  JDIMENSION crop_xoffset;	/* X offset of selected region */
+  JCROP_CODE crop_xoffset_set;	/* (negative measures from right edge) */
+  JDIMENSION crop_yoffset;	/* Y offset of selected region */
+  JCROP_CODE crop_yoffset_set;	/* (negative measures from bottom edge) */
 
   /* Internal workspace: caller should not touch these */
   int num_components;		/* # of components in workspace */
   jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
+  JDIMENSION output_width;	/* cropped destination dimensions */
+  JDIMENSION output_height;
+  JDIMENSION x_crop_offset;	/* destination crop offsets measured in iMCUs */
+  JDIMENSION y_crop_offset;
+  int iMCU_sample_width;	/* destination iMCU size */
+  int iMCU_sample_height;
 } jpeg_transform_info;
 
 
 #if TRANSFORMS_SUPPORTED
 
+/* Parse a crop specification (written in X11 geometry style) */
+EXTERN(boolean) jtransform_parse_crop_spec
+	JPP((jpeg_transform_info *info, const char *spec));
 /* Request any required workspace */
-EXTERN(void) jtransform_request_workspace
+EXTERN(boolean) jtransform_request_workspace
 	JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
 /* Adjust output image parameters */
 EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
@@ -106,10 +167,24 @@
 	     jvirt_barray_ptr *src_coef_arrays,
 	     jpeg_transform_info *info));
 /* Execute the actual transformation, if any */
-EXTERN(void) jtransform_execute_transformation
+EXTERN(void) jtransform_execute_transform
 	JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
 	     jvirt_barray_ptr *src_coef_arrays,
 	     jpeg_transform_info *info));
+/* Determine whether lossless transformation is perfectly
+ * possible for a specified image and transformation.
+ */
+EXTERN(boolean) jtransform_perfect_transform
+	JPP((JDIMENSION image_width, JDIMENSION image_height,
+	     int MCU_width, int MCU_height,
+	     JXFORM_CODE transform));
+
+/* jtransform_execute_transform used to be called
+ * jtransform_execute_transformation, but some compilers complain about
+ * routine names that long.  This macro is here to avoid breaking any
+ * old source code that uses the original name...
+ */
+#define jtransform_execute_transformation	jtransform_execute_transform
 
 #endif /* TRANSFORMS_SUPPORTED */
 
diff --git a/turbojpeg-mapfile b/turbojpeg-mapfile
index b2776f2..aa0b658 100755
--- a/turbojpeg-mapfile
+++ b/turbojpeg-mapfile
@@ -1,3 +1,4 @@
+TURBOJPEG_1.0
 {
 	global:
 		tjInitCompress;
@@ -11,3 +12,12 @@
 	local:
 		*;
 };
+
+TURBOJPEG_1.1
+{
+	global:
+		TJBUFSIZEYUV;
+		tjDecompressHeader2;
+		tjDecompressToYUV;
+		tjEncodeYUV;
+} TURBOJPEG_1.0;
diff --git a/turbojpeg.h b/turbojpeg.h
index c8458e8..b5359e1 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -1,6 +1,6 @@
 /* Copyright (C)2004 Landmark Graphics Corporation
  * Copyright (C)2005, 2006 Sun Microsystems, Inc.
- * Copyright (C)2009 D. R. Commander
+ * Copyright (C)2009-2011 D. R. Commander
  *
  * This library is free software and may be redistributed and/or modified under
  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -13,7 +13,8 @@
  * wxWindows Library License for more details.
  */
 
-#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE)
+#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) \
+	&& defined(_WIN32) && defined(DLLDEFINE)
 #define DLLEXPORT __declspec(dllexport)
 #else
 #define DLLEXPORT
@@ -21,6 +22,7 @@
 
 #define DLLCALL
 
+
 /* Subsampling */
 #define NUMSUBOPT 4
 
@@ -28,6 +30,7 @@
 #define TJ_411 TJ_420  /* for backward compatibility with VirtualGL <= 2.1.x,
                           TurboVNC <= 0.6, and TurboJPEG/IPP */
 
+
 /* Flags */
 #define TJ_BGR             1
   /* The components of each pixel in the source/destination bitmap are stored
@@ -52,7 +55,11 @@
      (64-bit IPP version only) */
 #define TJ_FASTUPSAMPLE  256
   /* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines
-     (libjpeg version only) */
+     (libjpeg and libjpeg-turbo versions only) */
+#define TJ_YUV           512
+  /* Nothing to see here.  Pay no attention to the man behind the curtain. */
+
+
 typedef void* tjhandle;
 
 #define TJPAD(p) (((p)+3)&(~3))
@@ -60,6 +67,7 @@
  #define max(a,b) ((a)>(b)?(a):(b))
 #endif
 
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -74,7 +82,8 @@
   and returns a handle to the instance.  Most applications will only
   need to call this once at the beginning of the program or once for each
   concurrent thread.  Don't try to create a new instance every time you
-  compress an image, because this will cause performance to suffer.
+  compress an image, because this may cause performance to suffer in some
+  TurboJPEG implementations.
 
   RETURNS: NULL on error
 */
@@ -89,39 +98,40 @@
 
   [INPUT] j = instance handle previously returned from a call to
      tjInitCompress()
-  [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in
-     RGB(A) or BGR(A) form
-  [INPUT] width =  width (in pixels) of the source image
+  [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
+     grayscale pixels to be compressed
+  [INPUT] width = width (in pixels) of the source image
   [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
      bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
      is padded to the nearest 32-bit boundary, such as is the case for Windows
-     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
-     as long as the pitch is greater than 0.)
+     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
+     width*pixelsize.
   [INPUT] height = height (in pixels) of the source image
   [INPUT] pixelsize = size (in bytes) of each pixel in the source image
-     RGBA and BGRA: 4, RGB and BGR: 3
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
-     the JPEG image.  Use the macro TJBUFSIZE(width, height) to determine
+     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
+  [INPUT] dstbuf = pointer to user-allocated image buffer that will receive
+     the JPEG image.  Use the TJBUFSIZE(width, height) function to determine
      the appropriate size for this buffer based on the image width and height.
-  [OUTPUT] size = pointer to unsigned long which receives the size (in bytes)
+  [OUTPUT] size = pointer to unsigned long that receives the size (in bytes)
      of the compressed image
-  [INPUT] jpegsubsamp = Specifies either 4:2:0, 4:2:2, or 4:4:4 subsampling.
-     When the image is converted from the RGB to YCbCr colorspace as part of the
-     JPEG compression process, every other Cb and Cr (chrominance) pixel can be
-     discarded to produce a smaller image with little perceptible loss of
-     image clarity (the human eye is more sensitive to small changes in
-     brightness than small changes in color.)
+  [INPUT] jpegsubsamp = Specifies either 4:2:0, 4:2:2, 4:4:4, or grayscale
+     subsampling.  When the image is converted from the RGB to YCbCr colorspace
+     as part of the JPEG compression process, every other Cb and Cr
+     (chrominance) pixel can be discarded to produce a smaller image with
+     little perceptible loss of image clarity (the human eye is more sensitive
+     to small changes in brightness than small changes in color.)
 
      TJ_420: 4:2:0 subsampling.  Discards every other Cb, Cr pixel in both
-        horizontal and vertical directions.
+        horizontal and vertical directions
      TJ_422: 4:2:2 subsampling.  Discards every other Cb, Cr pixel only in
-        the horizontal direction.
-     TJ_444: no subsampling.
+        the horizontal direction
+     TJ_444: no subsampling
      TJ_GRAYSCALE: Generate grayscale JPEG image
 
-  [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.)
+  [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive)
   [INPUT] flags = the bitwise OR of one or more of the flags described in the
-     "Flags" section above.
+     "Flags" section above
 
   RETURNS: 0 on success, -1 on error
 */
@@ -130,8 +140,77 @@
 	unsigned char *dstbuf, unsigned long *size,
 	int jpegsubsamp, int jpegqual, int flags);
 
+
+/*
+  unsigned long TJBUFSIZE(int width, int height)
+
+  Convenience function that returns the maximum size of the buffer required to
+  hold a JPEG image with the given width and height
+
+  RETURNS: -1 if arguments are out of bounds
+*/
 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
 
+
+/*
+  unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
+
+  Convenience function that returns the size of the buffer required to
+  hold a YUV planar image with the given width, height, and level of
+  chrominance subsampling
+
+  RETURNS: -1 if arguments are out of bounds
+*/
+DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
+  int subsamp);
+
+
+/*
+  int tjEncodeYUV(tjhandle j,
+     unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+     unsigned char *dstbuf, int subsamp, int flags)
+
+  This function uses the accelerated color conversion routines in TurboJPEG's
+  underlying codec to produce a planar YUV image that is suitable for X Video.
+  Specifically, if the chrominance components are subsampled along the
+  horizontal dimension, then the width of the luminance plane is padded to 2 in
+  the output image (same goes for the height of the luminance plane, if the
+  chrominance components are subsampled along the vertical dimension.)  Also,
+  each line of each plane in the output image is padded to 4 bytes.  Although
+  this will work with any subsampling option, it is really only useful in
+  combination with TJ_420, which produces an image compatible with the I420
+  (AKA "YUV420P") format.
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitCompress()
+  [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
+     grayscale pixels to be encoded
+  [INPUT] width = width (in pixels) of the source image
+  [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
+     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+     is padded to the nearest 32-bit boundary, such 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
+     width*pixelsize.
+  [INPUT] height = height (in pixels) of the source image
+  [INPUT] pixelsize = size (in bytes) of each pixel in the source image
+     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
+  [INPUT] dstbuf = pointer to user-allocated image buffer that will receive
+     the YUV image.  Use the TJBUFSIZEYUV(width, height, subsamp) function to
+     determine the appropriate size for this buffer based on the image width,
+     height, and level of subsampling.
+  [INPUT] subsamp = Specifies either 4:2:0, 4:2:2, 4:4:4, or grayscale
+     subsampling (see description under tjCompress())
+  [INPUT] flags = the bitwise OR of one or more of the flags described in the
+     "Flags" section above
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle j,
+	unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+	unsigned char *dstbuf, int subsamp, int flags);
+
+
 /*
   tjhandle tjInitDecompress(void)
 
@@ -139,7 +218,8 @@
   structures, and returns a handle to the instance.  Most applications will
   only need to call this once at the beginning of the program or once for each
   concurrent thread.  Don't try to create a new instance every time you
-  decompress an image, because this will cause performance to suffer.
+  decompress an image, because this may cause performance to suffer in some
+  TurboJPEG implementations.
 
   RETURNS: NULL on error
 */
@@ -147,20 +227,28 @@
 
 
 /*
-  int tjDecompressHeader(tjhandle j,
+  int tjDecompressHeader2(tjhandle j,
      unsigned char *srcbuf, unsigned long size,
-     int *width, int *height)
+     int *width, int *height, int *jpegsubsamp)
 
   [INPUT] j = instance handle previously returned from a call to
      tjInitDecompress()
-  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
-     to decompress
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing a JPEG image
   [INPUT] size = size of the JPEG image buffer (in bytes)
   [OUTPUT] width = width (in pixels) of the JPEG image
   [OUTPUT] height = height (in pixels) of the JPEG image
+  [OUTPUT] jpegsubsamp = type of chrominance subsampling used when compressing
+     the JPEG image
 
   RETURNS: 0 on success, -1 on error
 */
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle j,
+	unsigned char *srcbuf, unsigned long size,
+	int *width, int *height, int *jpegsubsamp);
+
+/*
+  Legacy version of the above function
+*/
 DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
 	unsigned char *srcbuf, unsigned long size,
 	int *width, int *height);
@@ -177,19 +265,20 @@
   [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
      to decompress
   [INPUT] size = size of the JPEG image buffer (in bytes)
-  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+  [INPUT] dstbuf = pointer to user-allocated image buffer that will receive
      the bitmap image.  This buffer should normally be pitch*height
      bytes in size, although this pointer may also be used to decompress into
      a specific region of a larger buffer.
-  [INPUT] width =  width (in pixels) of the destination image
-  [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the
-     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
-     is padded to the nearest 32-bit boundary, such as is the case for Windows
-     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
-     as long as the pitch is greater than 0.)
+  [INPUT] width = width (in pixels) of the destination image
+  [INPUT] pitch = bytes per line of the destination image (width*pixelsize if
+     the bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the
+     bitmap is padded to the nearest 32-bit boundary, such 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 width*pixelsize.
   [INPUT] height = height (in pixels) of the destination image
   [INPUT] pixelsize = size (in bytes) of each pixel in the destination image
-     RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3
+     RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
   [INPUT] flags = the bitwise OR of one or more of the flags described in the
      "Flags" section above.
 
@@ -202,6 +291,37 @@
 
 
 /*
+  int tjDecompressToYUV(tjhandle j,
+     unsigned char *srcbuf, unsigned long size,
+     unsigned char *dstbuf, int flags)
+
+  This function performs JPEG decompression but leaves out the color conversion
+  step, so a planar YUV image is generated instead of an RGB image.  The
+  padding of the planes in this image is the same as in tjEncodeYUV().
+  Note that, if the width or height of the output image is not a multiple of 8
+  (or a multiple of 16 along any dimension in which chrominance subsampling is
+  used), then an intermediate buffer copy will be performed within TurboJPEG.
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitDecompress()
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+     to decompress
+  [INPUT] size = size of the JPEG image buffer (in bytes)
+  [INPUT] dstbuf = pointer to user-allocated image buffer that will receive
+     the YUV image.  Use the TJBUFSIZEYUV(width, height, subsamp) function to
+     determine the appropriate size for this buffer based on the image width,
+     height, and level of subsampling.
+  [INPUT] flags = the bitwise OR of one or more of the flags described in the
+     "Flags" section above.
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle j,
+	unsigned char *srcbuf, unsigned long size,
+	unsigned char *dstbuf, int flags);
+
+
+/*
   int tjDestroy(tjhandle h)
 
   Frees structures associated with a compression or decompression instance
@@ -221,6 +341,7 @@
 */
 DLLEXPORT char* DLLCALL tjGetErrorStr(void);
 
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/turbojpegl.c b/turbojpegl.c
index eeaedd1..5cc5437 100644
--- a/turbojpegl.c
+++ b/turbojpegl.c
@@ -1,6 +1,6 @@
 /* Copyright (C)2004 Landmark Graphics Corporation
  * Copyright (C)2005 Sun Microsystems, Inc.
- * Copyright (C)2009 D. R. Commander
+ * Copyright (C)2009-2011 D. R. Commander
  *
  * This library is free software and may be redistributed and/or modified under
  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -18,11 +18,18 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#define JPEG_INTERNALS
 #include <jpeglib.h>
 #include <jerror.h>
 #include <setjmp.h>
 #include "./turbojpeg.h"
 
+#ifndef min
+ #define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
+
 
 // Error handling
 
@@ -61,11 +68,11 @@
 
 static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
 static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
+static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1};
 
-#define _throw(c) {sprintf(lasterror, "%s", c);  return -1;}
-#define _catch(f) {if((f)==-1) return -1;}
+#define _throw(c) {sprintf(lasterror, "%s", c);  retval=-1;  goto bailout;}
 #define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
-	if(!j) _throw("Invalid handle");
+	if(!j) {sprintf(lasterror, "Invalid handle");  return -1;}
 
 
 // CO
@@ -93,7 +100,7 @@
 	if(setjmp(j->jerr.jb))
 	{ // this will execute if LIBJPEG has an error
 		if(j) free(j);  return NULL;
-  }
+	}
 
 	jpeg_create_compress(&j->cinfo);
 	j->cinfo.dest=&j->jdms;
@@ -105,26 +112,64 @@
 	return (tjhandle)j;
 }
 
+
 DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
 {
-	// This allows enough room in case the image doesn't compress
-	return ((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
+	unsigned long retval=0;
+	if(width<1 || height<1)
+		_throw("Invalid argument in TJBUFSIZE()");
+
+	// This allows for rare corner cases in which a JPEG image can actually be
+	// larger than the uncompressed input (we wouldn't mention it if it hadn't
+	// happened before.)
+	retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
+
+	bailout:
+	return retval;
 }
 
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
+	int subsamp)
+{
+	unsigned long retval=0;
+	int pw, ph, cw, ch;
+	if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
+		_throw("Invalid argument in TJBUFSIZEYUV()");
+	pw=PAD(width, hsampfactor[subsamp]);
+	ph=PAD(height, vsampfactor[subsamp]);
+	cw=pw/hsampfactor[subsamp];  ch=ph/vsampfactor[subsamp];
+	retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
+
+	bailout:
+	return retval;
+}
+
+
 DLLEXPORT int DLLCALL tjCompress(tjhandle h,
 	unsigned char *srcbuf, int width, int pitch, int height, int ps,
 	unsigned char *dstbuf, unsigned long *size,
 	int jpegsub, int qual, int flags)
 {
-	int i;  JSAMPROW *row_pointer=NULL;
+	int i, retval=0;  JSAMPROW *row_pointer=NULL;
+	JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS];
+	JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
+	JSAMPROW *outbuf[MAX_COMPONENTS];
 
 	checkhandle(h);
 
+	for(i=0; i<MAX_COMPONENTS; i++)
+	{
+		tmpbuf[i]=NULL;  _tmpbuf[i]=NULL;
+		tmpbuf2[i]=NULL;  _tmpbuf2[i]=NULL;  outbuf[i]=NULL;
+	}
+
 	if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
 		|| dstbuf==NULL || size==NULL
 		|| jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
 		_throw("Invalid argument in tjCompress()");
-	if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
+	if(ps!=3 && ps!=4 && ps!=1)
+		_throw("This compressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale input");
 	if(!j->initc) _throw("Instance has not been initialized for compression");
 
 	if(pitch==0) pitch=width*ps;
@@ -133,8 +178,9 @@
 	j->cinfo.image_height = height;
 	j->cinfo.input_components = ps;
 
+	if(ps==1) j->cinfo.in_color_space = JCS_GRAYSCALE;
 	#if JCS_EXTENSIONS==1
-	j->cinfo.in_color_space = JCS_EXT_RGB;
+	else j->cinfo.in_color_space = JCS_EXT_RGB;
 	if(ps==3 && (flags&TJ_BGR))
 		j->cinfo.in_color_space = JCS_EXT_BGR;
 	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
@@ -155,9 +201,9 @@
 
 	if(setjmp(j->jerr.jb))
 	{  // this will execute if LIBJPEG has an error
-		if(row_pointer) free(row_pointer);
-		return -1;
-  }
+		retval=-1;
+		goto bailout;
+	}
 
 	jpeg_set_defaults(&j->cinfo);
 
@@ -179,25 +225,124 @@
 	j->jdms.next_output_byte = dstbuf;
 	j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
 
-	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
-		_throw("Memory allocation failed in tjInitCompress()");
-	for(i=0; i<height; i++)
-	{
-		if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
-		else row_pointer[i]= &srcbuf[i*pitch];
-	}
 	jpeg_start_compress(&j->cinfo, TRUE);
-	while(j->cinfo.next_scanline<j->cinfo.image_height)
+	if(flags&TJ_YUV)
 	{
-		jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
-			j->cinfo.image_height-j->cinfo.next_scanline);
-	}
-	jpeg_finish_compress(&j->cinfo);
-	*size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
-		-(unsigned long)(j->jdms.free_in_buffer);
+		j_compress_ptr cinfo=&j->cinfo;
+		int row;
+		int pw=PAD(width, cinfo->max_h_samp_factor);
+		int ph=PAD(height, cinfo->max_v_samp_factor);
+		int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
+		jpeg_component_info *compptr;
+		JSAMPLE *ptr=dstbuf;  unsigned long yuvsize=0;
 
+		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL)
+			_throw("Memory allocation failed in tjCompress()");
+		for(i=0; i<height; i++)
+		{
+			if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
+			else row_pointer[i]= &srcbuf[i*pitch];
+		}
+		if(height<ph)
+			for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1];
+
+		for(i=0; i<cinfo->num_components; i++)
+		{
+			compptr=&cinfo->comp_info[i];
+			_tmpbuf[i]=(JSAMPLE *)malloc(
+				PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
+					/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16);
+			if(!_tmpbuf[i]) _throw("Memory allocation failure");
+			tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor);
+			if(!tmpbuf[i]) _throw("Memory allocation failure");
+			for(row=0; row<cinfo->max_v_samp_factor; row++)
+			{
+				unsigned char *_tmpbuf_aligned=
+					(unsigned char *)PAD((size_t)_tmpbuf[i], 16);
+				tmpbuf[i][row]=&_tmpbuf_aligned[
+					PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE)
+						/compptr->h_samp_factor, 16) * row];
+			}
+			_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16)
+				* compptr->v_samp_factor + 16);
+			if(!_tmpbuf2[i]) _throw("Memory allocation failure");
+			tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor);
+			if(!tmpbuf2[i]) _throw("Memory allocation failure");
+			for(row=0; row<compptr->v_samp_factor; row++)
+			{
+				unsigned char *_tmpbuf2_aligned=
+					(unsigned char *)PAD((size_t)_tmpbuf2[i], 16);
+				tmpbuf2[i][row]=&_tmpbuf2_aligned[
+					PAD(compptr->width_in_blocks*DCTSIZE, 16) * row];
+			}
+			cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor;
+			ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor;
+			outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]);
+			if(!outbuf[i]) _throw("Memory allocation failure");
+			for(row=0; row<ch[i]; row++)
+			{
+				outbuf[i][row]=ptr;
+				ptr+=PAD(cw[i], 4);
+			}
+		}
+		yuvsize=(unsigned long)(ptr-dstbuf);
+
+		for(row=0; row<ph; row+=cinfo->max_v_samp_factor)
+		{
+			(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf,
+				0, cinfo->max_v_samp_factor);
+			(cinfo->downsample->downsample)(cinfo, tmpbuf, 0, tmpbuf2, 0);
+			for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components;
+				i++, compptr++)
+				jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i],
+					row*compptr->v_samp_factor/cinfo->max_v_samp_factor,
+					compptr->v_samp_factor, cw[i]);
+		}
+		*size=yuvsize;
+		cinfo->next_scanline+=height;
+		jpeg_abort_compress(&j->cinfo);
+	}
+	else
+	{
+		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
+			_throw("Memory allocation failed in tjCompress()");
+		for(i=0; i<height; i++)
+		{
+			if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
+			else row_pointer[i]= &srcbuf[i*pitch];
+		}
+		while(j->cinfo.next_scanline<j->cinfo.image_height)
+		{
+			jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
+				j->cinfo.image_height-j->cinfo.next_scanline);
+		}
+		jpeg_finish_compress(&j->cinfo);
+		*size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)
+			-(unsigned long)(j->jdms.free_in_buffer);
+	}
+
+	bailout:
+	if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
 	if(row_pointer) free(row_pointer);
-	return 0;
+	for(i=0; i<MAX_COMPONENTS; i++)
+	{
+		if(tmpbuf[i]!=NULL) free(tmpbuf[i]);
+		if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]);
+		if(tmpbuf2[i]!=NULL) free(tmpbuf2[i]);
+		if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]);
+		if(outbuf[i]!=NULL) free(outbuf[i]);
+	}
+	return retval;
+}
+
+
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
+	unsigned char *srcbuf, int width, int pitch, int height, int ps,
+	unsigned char *dstbuf, int subsamp, int flags)
+{
+	unsigned long size;
+	return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size,
+		subsamp, 0, flags|TJ_YUV);
 }
 
 
@@ -232,7 +377,7 @@
 	if(setjmp(j->jerr.jb))
 	{ // this will execute if LIBJPEG has an error
 		free(j);  return NULL;
-  }
+	}
 
 	jpeg_create_decompress(&j->dinfo);
 	j->dinfo.src=&j->jsms;
@@ -247,14 +392,16 @@
 }
 
 
-DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
 	unsigned char *srcbuf, unsigned long size,
-	int *width, int *height)
+	int *width, int *height, int *jpegsub)
 {
+	int i, k, retval=0;
+
 	checkhandle(h);
 
-	if(srcbuf==NULL || size<=0 || width==NULL || height==NULL)
-		_throw("Invalid argument in tjDecompressHeader()");
+	if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
+		_throw("Invalid argument in tjDecompressHeader2()");
 	if(!j->initd) _throw("Instance has not been initialized for decompression");
 
 	if(setjmp(j->jerr.jb))
@@ -268,11 +415,45 @@
 	jpeg_read_header(&j->dinfo, TRUE);
 
 	*width=j->dinfo.image_width;  *height=j->dinfo.image_height;
+	*jpegsub=-1;
+	for(i=0; i<NUMSUBOPT; i++)
+	{
+		if(j->dinfo.num_components==pixelsize[i])
+		{
+			if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i]
+				&& j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i])
+			{
+				int match=0;
+				for(k=1; k<j->dinfo.num_components; k++)
+				{
+					if(j->dinfo.comp_info[k].h_samp_factor==1
+						&& j->dinfo.comp_info[k].v_samp_factor==1)
+						match++;
+				}
+				if(match==j->dinfo.num_components-1)
+				{
+					*jpegsub=i;  break;
+				}
+			}
+		}
+	}
 
 	jpeg_abort_decompress(&j->dinfo);
 
+	if(*jpegsub<0) _throw("Could not determine subsampling type for JPEG image");
 	if(*width<1 || *height<1) _throw("Invalid data returned in header");
-	return 0;
+
+	bailout:
+	return retval;
+}
+
+
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
+	unsigned char *srcbuf, unsigned long size,
+	int *width, int *height)
+{
+	int jpegsub;
+	return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub);
 }
 
 
@@ -281,14 +462,23 @@
 	unsigned char *dstbuf, int width, int pitch, int height, int ps,
 	int flags)
 {
-	int i;  JSAMPROW *row_pointer=NULL;
+	int i, row, retval=0;  JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
+	int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
+		tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
+	JSAMPLE *_tmpbuf=NULL;  JSAMPROW *tmpbuf[MAX_COMPONENTS];
 
 	checkhandle(h);
 
+	for(i=0; i<MAX_COMPONENTS; i++)
+	{
+		tmpbuf[i]=NULL;  outbuf[i]=NULL;
+	}
+
 	if(srcbuf==NULL || size<=0
 		|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
 		_throw("Invalid argument in tjDecompress()");
-	if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
+	if(ps!=3 && ps!=4 && ps!=1)
+		_throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
 	if(!j->initd) _throw("Instance has not been initialized for decompression");
 
 	if(pitch==0) pitch=width*ps;
@@ -299,25 +489,72 @@
 
 	if(setjmp(j->jerr.jb))
 	{  // this will execute if LIBJPEG has an error
-		if(row_pointer) free(row_pointer);
-		return -1;
-  }
+		retval=-1;
+		goto bailout;
+	}
 
 	j->jsms.bytes_in_buffer = size;
 	j->jsms.next_input_byte = srcbuf;
 
 	jpeg_read_header(&j->dinfo, TRUE);
 
-	if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
-		_throw("Memory allocation failed in tjInitDecompress()");
-	for(i=0; i<height; i++)
+	if(flags&TJ_YUV)
 	{
-		if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
-		else row_pointer[i]= &dstbuf[i*pitch];
+		j_decompress_ptr dinfo=&j->dinfo;
+		JSAMPLE *ptr=dstbuf;
+
+		for(i=0; i<dinfo->num_components; i++)
+		{
+			jpeg_component_info *compptr=&dinfo->comp_info[i];
+			int ih;
+			iw[i]=compptr->width_in_blocks*DCTSIZE;
+			ih=compptr->height_in_blocks*DCTSIZE;
+			cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
+				*compptr->h_samp_factor/dinfo->max_h_samp_factor;
+			ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
+				*compptr->v_samp_factor/dinfo->max_v_samp_factor;
+			if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
+			th[i]=compptr->v_samp_factor*DCTSIZE;
+			tmpbufsize+=iw[i]*th[i];
+			if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
+				_throw("Memory allocation failed in tjDecompress()");
+			for(row=0; row<ch[i]; row++)
+			{
+				outbuf[i][row]=ptr;
+				ptr+=PAD(cw[i], 4);
+			}
+		}
+		if(usetmpbuf)
+		{
+			if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
+				_throw("Memory allocation failed in tjDecompress()");
+			ptr=_tmpbuf;
+			for(i=0; i<dinfo->num_components; i++)
+			{
+				if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
+					_throw("Memory allocation failed in tjDecompress()");
+				for(row=0; row<th[i]; row++)
+				{
+					tmpbuf[i][row]=ptr;
+					ptr+=iw[i];
+				}
+			}
+		}
+	}
+	else
+	{
+		if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
+			_throw("Memory allocation failed in tjDecompress()");
+		for(i=0; i<height; i++)
+		{
+			if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
+			else row_pointer[i]= &dstbuf[i*pitch];
+		}
 	}
 
+	if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
 	#if JCS_EXTENSIONS==1
-	j->dinfo.out_color_space = JCS_EXT_RGB;
+	else j->dinfo.out_color_space = JCS_EXT_RGB;
 	if(ps==3 && (flags&TJ_BGR))
 		j->dinfo.out_color_space = JCS_EXT_BGR;
 	else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
@@ -331,18 +568,68 @@
 	#else
 	#error "TurboJPEG requires JPEG colorspace extensions"
 	#endif
+
 	if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
+	if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
 
 	jpeg_start_decompress(&j->dinfo);
-	while(j->dinfo.output_scanline<j->dinfo.output_height)
+	if(flags&TJ_YUV)
 	{
-		jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
-			j->dinfo.output_height-j->dinfo.output_scanline);
+		j_decompress_ptr dinfo=&j->dinfo;
+		for(row=0; row<dinfo->output_height;
+			row+=dinfo->max_v_samp_factor*DCTSIZE)
+		{
+			JSAMPARRAY yuvptr[MAX_COMPONENTS];
+			int crow[MAX_COMPONENTS];
+			for(i=0; i<dinfo->num_components; i++)
+			{
+				jpeg_component_info *compptr=&dinfo->comp_info[i];
+				crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor;
+				if(usetmpbuf) yuvptr[i]=tmpbuf[i];
+				else yuvptr[i]=&outbuf[i][crow[i]];
+			}
+			jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE);
+			if(usetmpbuf)
+			{
+				int j;
+				for(i=0; i<dinfo->num_components; i++)
+				{
+					for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
+					{
+						memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]);
+					}
+				}
+			}
+		}
+	}
+	else
+	{
+		while(j->dinfo.output_scanline<j->dinfo.output_height)
+		{
+			jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
+				j->dinfo.output_height-j->dinfo.output_scanline);
+		}
 	}
 	jpeg_finish_decompress(&j->dinfo);
 
+	bailout:
+	if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
+	for(i=0; i<MAX_COMPONENTS; i++)
+	{
+		if(tmpbuf[i]) free(tmpbuf[i]);
+		if(outbuf[i]) free(outbuf[i]);
+	}
+	if(_tmpbuf) free(_tmpbuf);
 	if(row_pointer) free(row_pointer);
-	return 0;
+	return retval;
+}
+
+
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
+	unsigned char *srcbuf, unsigned long size,
+	unsigned char *dstbuf, int flags)
+{
+	return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
 }
 
 
diff --git a/usage.doc b/usage.txt
similarity index 86%
rename from usage.doc
rename to usage.txt
index 8c4970a..2abfbea 100644
--- a/usage.doc
+++ b/usage.txt
@@ -12,19 +12,9 @@
 
 INTRODUCTION
 
-These programs implement JPEG image compression and decompression.  JPEG
-(pronounced "jay-peg") is a standardized compression method for full-color
-and gray-scale images.  JPEG is designed to handle "real-world" scenes,
-for example scanned photographs.  Cartoons, line drawings, and other
-non-realistic images are not JPEG's strong suit; on that sort of material
-you may get poor image quality and/or little compression.
-
-JPEG is lossy, meaning that the output image is not necessarily identical to
-the input image.  Hence you should not use JPEG if you have to have identical
-output bits.  However, on typical real-world images, very good compression
-levels can be obtained with no visible change, and amazingly high compression
-is possible if you can tolerate a low-quality image.  You can trade off image
-quality against file size by adjusting the compressor's "quality" setting.
+These programs implement JPEG image encoding, decoding, and transcoding.
+JPEG (pronounced "jay-peg") is a standardized compression method for
+full-color and gray-scale images.
 
 
 GENERAL USAGE
@@ -48,7 +38,7 @@
 i.e., both the input and output files are named on the command line.  This
 style is a little more foolproof, and it loses no functionality if you don't
 have pipes.  (You can get this style on Unix too, if you prefer, by defining
-TWO_FILE_COMMANDLINE when you compile the programs; see install.doc.)
+TWO_FILE_COMMANDLINE when you compile the programs; see install.txt.)
 
 You can also say:
 	cjpeg [switches] -outfile jpegfile  imagefile
@@ -76,7 +66,7 @@
 
 The basic command line switches for cjpeg are:
 
-	-quality N	Scale quantization tables to adjust image quality.
+	-quality N[,...]  Scale quantization tables to adjust image quality.
 			Quality is 0 (worst) to 100 (best); default is 75.
 			(See below for more info.)
 
@@ -128,18 +118,50 @@
 other JPEG programs may be unable to decode the resulting file.  Use -baseline
 if you need to ensure compatibility at low quality values.)
 
+The -quality option has been extended in this version of cjpeg to support
+separate quality settings for luminance and chrominance (or, in general,
+separate settings for every quantization table slot.)  The principle is the
+same as chrominance subsampling:  since the human eye is more sensitive to
+spatial changes in brightness than spatial changes in color, the chrominance
+components can be quantized more than the luminance components without
+incurring any visible image quality loss.  However, unlike subsampling, this
+feature reduces data in the frequency domain instead of the spatial domain,
+which allows for more fine-grained control.  This option is useful in
+quality-sensitive applications, for which the artifacts generated by
+subsampling may be unacceptable.
+
+The -quality option accepts a comma-separated list of parameters, which
+respectively refer to the quality levels that should be assigned to the
+quantization table slots.  If there are more q-table slots than parameters,
+then the last parameter is replicated.  Thus, if only one quality parameter is
+given, this is used for both luminance and chrominance (slots 0 and 1,
+respectively), preserving the legacy behavior of cjpeg v6b and prior.  More (or
+customized) quantization tables can be set with the -qtables option and
+assigned to components with the -qslots option (see the "wizard" switches
+below.)
+
+JPEG  files  generated  with separate luminance and chrominance quality are
+fully compliant with standard JPEG decoders.
+
+CAUTION: For this setting to be useful, be sure to pass an argument of
+-sample 1x1 to cjpeg to disable chrominance subsampling.  Otherwise, the
+default subsampling level (2x2, AKA "4:2:0") will be used.
+
 The -progressive switch creates a "progressive JPEG" file.  In this type of
 JPEG file, the data is stored in multiple scans of increasing quality.  If the
 file is being transmitted over a slow communications link, the decoder can use
 the first scan to display a low-quality image very quickly, and can then
 improve the display with each subsequent scan.  The final image is exactly
 equivalent to a standard JPEG file of the same quality setting, and the total
-file size is about the same --- often a little smaller.  CAUTION: progressive
-JPEG is not yet widely implemented, so many decoders will be unable to view a
-progressive JPEG file at all.
+file size is about the same --- often a little smaller.
 
 Switches for advanced users:
 
+	-arithmetic	Use arithmetic coding.  CAUTION: arithmetic coded JPEG
+			is not yet widely implemented, so many decoders will
+			be unable to view an arithmetic coded JPEG file at
+			all.
+
 	-dct int	Use integer DCT method (default).
 	-dct fast	Use fast integer DCT (less accurate).
 	-dct float	Use floating-point DCT method.
@@ -203,7 +225,7 @@
 
 The "wizard" switches are intended for experimentation with JPEG.  If you
 don't know what you are doing, DON'T USE THEM.  These switches are documented
-further in the file wizard.doc.
+further in the file wizard.txt.
 
 
 DJPEG DETAILS
@@ -332,9 +354,10 @@
 is often a lot more than it is on larger files.  (At present, -optimize
 mode is always selected when generating progressive JPEG files.)
 
-GIF input files are no longer supported, to avoid the Unisys LZW patent.
-Use a Unisys-licensed program if you need to read a GIF file.  (Conversion
-of GIF files to JPEG is usually a bad idea anyway.)
+Support for GIF input files was removed in cjpeg v6b due to concerns over
+the Unisys LZW patent.  Although this patent expired in 2006, cjpeg still
+lacks GIF support, for these historical reasons.  (Conversion of GIF files to
+JPEG is usually a bad idea anyway.)
 
 
 HINTS FOR DJPEG
@@ -424,6 +447,7 @@
 jpegtran accepts a subset of the switches recognized by cjpeg:
 	-optimize	Perform optimization of entropy encoding parameters.
 	-progressive	Create progressive JPEG file.
+	-arithmetic	Use arithmetic coding.
 	-restart N	Emit a JPEG restart marker every N MCU rows, or every
 			N MCU blocks if "B" is attached to the number.
 	-scans file	Use the scan script given in the specified text file.
@@ -466,7 +490,26 @@
 "-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by
 "-rot 180 -trim" trims both edges.
 
-Another not-strictly-lossless transformation switch is:
+If you are only interested in perfect transformations, add the -perfect switch:
+	-perfect	Fail with an error if the transformation is not
+			perfect.
+For example, you may want to do
+  jpegtran -rot 90 -perfect foo.jpg || djpeg foo.jpg | pnmflip -r90 | cjpeg
+to do a perfect rotation, if available, or an approximated one if not.
+
+This version of jpegtran also offers a lossless crop option, which discards
+data outside of a given image region but losslessly preserves what is inside.
+Like the rotate and flip transforms, lossless crop is restricted by the current
+JPEG format; the upper left corner of the selected region must fall on an iMCU
+boundary.  If it doesn't, then it is silently moved up and/or left to the
+nearest iMCU boundary (the lower right corner is unchanged.)
+
+The image can be losslessly cropped by giving the switch:
+	-crop WxH+X+Y	Crop to a rectangular region of width W and height H,
+			starting at point X,Y.
+
+Other not-strictly-lossless transformation switches are:
+
 	-grayscale	Force grayscale output.
 This option discards the chrominance channels if the input image is YCbCr
 (ie, a standard color JPEG), resulting in a grayscale JPEG file.  The
@@ -483,12 +526,12 @@
 			suppresses all comments and other excess baggage
 			present in the source file.
 	-copy comments	Copy only comment markers.  This setting copies
-			comments from the source file, but discards
-			any other inessential data. 
+			comments from the source file but discards
+			any other data that is inessential for image display.
 	-copy all	Copy all extra markers.  This setting preserves
 			miscellaneous markers found in the source file, such
-			as JFIF thumbnails and Photoshop settings.  In some
-			files these extra markers can be sizable.
+			as JFIF thumbnails, Exif data, and Photoshop settings.
+			In some files, these extra markers can be sizable.
 The default behavior is -copy comments.  (Note: in IJG releases v6 and v6a,
 jpegtran always did the equivalent of -copy none.)
 
@@ -515,7 +558,10 @@
 
 rdjpgcom searches a JPEG file and prints the contents of any COM blocks on
 standard output.  The command line syntax is
-	rdjpgcom [-verbose] [inputfilename]
+	rdjpgcom [-raw] [-verbose] [inputfilename]
+The switch "-raw" (or just "-r") causes rdjpgcom to output non-printable
+characters in JPEG comments.  These characters are normally escaped for
+security reasons.
 The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG
 image dimensions.  If you omit the input file name from the command line,
 the JPEG file is read from standard input.  (This may not work on some
diff --git a/win/Makefile b/win/Makefile
deleted file mode 100755
index a63faf5..0000000
--- a/win/Makefile
+++ /dev/null
@@ -1,283 +0,0 @@
-vpath %.c simd
-vpath %.asm simd
-
-include win/Makerules
-
-TARGETS = $(ODIR)/jpeg62.dll \
-          $(ODIR)/jpeg.lib \
-          $(ODIR)/jpeg-static.lib \
-          $(ODIR)/cjpeg.exe \
-          $(ODIR)/djpeg.exe \
-          $(ODIR)/jpegtran.exe \
-          $(ODIR)/rdjpgcom.exe \
-          $(ODIR)/wrjpgcom.exe \
-          $(ODIR)/turbojpeg.dll \
-          $(ODIR)/turbojpeg.lib \
-          $(ODIR)/turbojpeg-static.lib \
-          $(ODIR)/jpgtest.exe \
-          $(ODIR)/jpegut.exe
-
-LOBJS = $(ODIR)/jcapimin.obj \
-        $(ODIR)/jcapistd.obj \
-        $(ODIR)/jccoefct.obj \
-        $(ODIR)/jccolor.obj \
-        $(ODIR)/jcdctmgr.obj \
-        $(ODIR)/jchuff.obj \
-        $(ODIR)/jcinit.obj \
-        $(ODIR)/jcmainct.obj \
-        $(ODIR)/jcmarker.obj \
-        $(ODIR)/jcmaster.obj \
-        $(ODIR)/jcomapi.obj \
-        $(ODIR)/jcparam.obj \
-        $(ODIR)/jcphuff.obj \
-        $(ODIR)/jcprepct.obj \
-        $(ODIR)/jcsample.obj \
-        $(ODIR)/jctrans.obj \
-        $(ODIR)/jdapimin.obj \
-        $(ODIR)/jdapistd.obj \
-        $(ODIR)/jdatadst.obj \
-        $(ODIR)/jdatasrc.obj \
-        $(ODIR)/jdcoefct.obj \
-        $(ODIR)/jdcolor.obj \
-        $(ODIR)/jddctmgr.obj \
-        $(ODIR)/jdhuff.obj \
-        $(ODIR)/jdinput.obj \
-        $(ODIR)/jdmainct.obj \
-        $(ODIR)/jdmarker.obj \
-        $(ODIR)/jdmaster.obj \
-        $(ODIR)/jdmerge.obj \
-        $(ODIR)/jdphuff.obj \
-        $(ODIR)/jdpostct.obj \
-        $(ODIR)/jdsample.obj \
-        $(ODIR)/jdtrans.obj \
-        $(ODIR)/jerror.obj \
-        $(ODIR)/jfdctflt.obj \
-        $(ODIR)/jfdctfst.obj \
-        $(ODIR)/jfdctint.obj \
-        $(ODIR)/jidctflt.obj \
-        $(ODIR)/jidctfst.obj \
-        $(ODIR)/jidctint.obj \
-        $(ODIR)/jidctred.obj \
-        $(ODIR)/jquant1.obj \
-        $(ODIR)/jquant2.obj \
-        $(ODIR)/jutils.obj \
-        $(ODIR)/jmemmgr.obj \
-        $(ODIR)/jmemnobs.obj
-
-ifeq ($(WITH_SIMD), yes)
-
- ifeq ($(WIN64), yes)
-  SIMD_OBJS = $(ODIR)/jfsseflt-64.obj \
-              $(ODIR)/jccolss2-64.obj \
-              $(ODIR)/jdcolss2-64.obj \
-              $(ODIR)/jcsamss2-64.obj \
-              $(ODIR)/jdsamss2-64.obj \
-              $(ODIR)/jdmerss2-64.obj \
-              $(ODIR)/jcqnts2i-64.obj \
-              $(ODIR)/jfss2fst-64.obj \
-              $(ODIR)/jfss2int-64.obj \
-              $(ODIR)/jiss2red-64.obj \
-              $(ODIR)/jiss2int-64.obj \
-              $(ODIR)/jiss2fst-64.obj \
-              $(ODIR)/jcqnts2f-64.obj \
-              $(ODIR)/jiss2flt-64.obj
-  LOBJS := $(LOBJS) $(ODIR)/jsimd_x86_64.obj
- else
-  SIMD_OBJS = $(ODIR)/jsimdcpu.obj \
-              $(ODIR)/jccolmmx.obj \
-              $(ODIR)/jdcolmmx.obj \
-              $(ODIR)/jcsammmx.obj \
-              $(ODIR)/jdsammmx.obj \
-              $(ODIR)/jdmermmx.obj \
-              $(ODIR)/jcqntmmx.obj \
-              $(ODIR)/jfmmxfst.obj \
-              $(ODIR)/jfmmxint.obj \
-              $(ODIR)/jimmxred.obj \
-              $(ODIR)/jimmxint.obj \
-              $(ODIR)/jimmxfst.obj \
-              $(ODIR)/jcqnt3dn.obj \
-              $(ODIR)/jf3dnflt.obj \
-              $(ODIR)/ji3dnflt.obj \
-              $(ODIR)/jcqntsse.obj \
-              $(ODIR)/jfsseflt.obj \
-              $(ODIR)/jisseflt.obj \
-              $(ODIR)/jccolss2.obj \
-              $(ODIR)/jdcolss2.obj \
-              $(ODIR)/jcsamss2.obj \
-              $(ODIR)/jdsamss2.obj \
-              $(ODIR)/jdmerss2.obj \
-              $(ODIR)/jcqnts2i.obj \
-              $(ODIR)/jfss2fst.obj \
-              $(ODIR)/jfss2int.obj \
-              $(ODIR)/jiss2red.obj \
-              $(ODIR)/jiss2int.obj \
-              $(ODIR)/jiss2fst.obj \
-              $(ODIR)/jcqnts2f.obj \
-              $(ODIR)/jiss2flt.obj
-  LOBJS := $(LOBJS) $(ODIR)/jsimd_i386.obj
- endif
-
-else
-
- LOBJS := $(LOBJS) $(ODIR)/jsimd_none.obj
-
-endif
-
-LOBJSSTATIC := $(subst .obj,-static.obj,$(LOBJS))
-LOBJS := $(LOBJS) $(SIMD_OBJS)
-LOBJSSTATIC := $(LOBJSSTATIC) $(SIMD_OBJS)
-
-OBJS := $(LOBJS) $(LOBJSSTATIC) \
-        $(ODIR)/cdjpeg.obj \
-        $(ODIR)/cjpeg.obj \
-        $(ODIR)/djpeg.obj \
-        $(ODIR)/jpegtran.obj \
-        $(ODIR)/rdbmp.obj \
-        $(ODIR)/rdcolmap.obj \
-        $(ODIR)/rdgif.obj \
-        $(ODIR)/rdjpgcom.obj \
-        $(ODIR)/rdppm.obj \
-        $(ODIR)/rdtarga.obj \
-        $(ODIR)/rdswitch.obj \
-        $(ODIR)/rdtarga.obj \
-        $(ODIR)/transupp.obj \
-        $(ODIR)/wrbmp.obj \
-        $(ODIR)/wrgif.obj \
-        $(ODIR)/wrppm.obj \
-        $(ODIR)/wrtarga.obj \
-        $(ODIR)/wrjpgcom.obj \
-        $(ODIR)/turbojpegl-static.obj \
-        $(ODIR)/turbojpegl-dll.obj \
-        $(ODIR)/jpgtest.obj \
-        $(ODIR)/jpegut.obj \
-        $(ODIR)/bmp-static.obj
-
-all: $(TARGETS)
-
-clean: testclean
-	-$(RM) $(TARGETS) $(OBJS)
-
-HDRS := $(wildcard *.h)
-$(OBJS): $(HDRS)
-
-ifeq ($(WITH_SIMD), yes)
-SIMD_HDRS := $(wildcard simd/*.inc)
-$(SIMD_OBJS): $(SIMD_HDRS)
-
-ifeq ($(WIN64), yes)
-$(ODIR)/jccolss2-64.obj: simd/jcclrss2-64.asm
-$(ODIR)/jdcolss2-64.obj: simd/jdclrss2-64.asm
-$(ODIR)/jdmerss2-64.obj: simd/jdmrgss2-64.asm
-else
-$(ODIR)/jccolmmx.obj: simd/jcclrmmx.asm
-$(ODIR)/jccolss2.obj: simd/jcclrss2.asm
-$(ODIR)/jdcolmmx.obj: simd/jdclrmmx.asm
-$(ODIR)/jdcolss2.obj: simd/jdclrss2.asm
-$(ODIR)/jdmermmx.obj: simd/jdmrgmmx.asm
-$(ODIR)/jdmerss2.obj: simd/jdmrgss2.asm
-endif
-
-endif
-
-$(ODIR)/jpeg-static.lib: $(LOBJSSTATIC)
-	$(AR) -out:$@ $^
-
-$(ODIR)/jpeg62.dll $(ODIR)/jpeg.lib: $(LOBJS) win/jpeg.def
-	$(LINK) $(LDFLAGS) -dll -out:$(ODIR)/jpeg62.dll -implib:$(ODIR)/jpeg.lib \
-		-def:win/jpeg.def $(LOBJS)
-
-$(ODIR)/cjpeg.exe: $(ODIR)/cdjpeg.obj $(ODIR)/cjpeg.obj $(ODIR)/rdbmp.obj \
-	$(ODIR)/rdgif.obj $(ODIR)/rdppm.obj $(ODIR)/rdswitch.obj \
-	$(ODIR)/rdtarga.obj $(ODIR)/jpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-
-$(ODIR)/djpeg.exe: $(ODIR)/cdjpeg.obj $(ODIR)/djpeg.obj $(ODIR)/rdcolmap.obj \
-	$(ODIR)/rdswitch.obj $(ODIR)/wrbmp.obj $(ODIR)/wrgif.obj $(ODIR)/wrppm.obj \
-	$(ODIR)/wrtarga.obj $(ODIR)/jpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-
-$(ODIR)/jpegtran.exe: $(ODIR)/cdjpeg.obj $(ODIR)/jpegtran.obj \
-	$(ODIR)/rdswitch.obj $(ODIR)/transupp.obj $(ODIR)/jpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-$(ODIR)/rdjpgcom.exe: $(ODIR)/rdjpgcom.obj $(ODIR)/jpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-$(ODIR)/wrjpgcom.exe: $(ODIR)/wrjpgcom.obj $(ODIR)/jpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-
-$(ODIR)/turbojpeg-static.lib: $(ODIR)/turbojpegl-static.obj $(LOBJSSTATIC)
-	$(AR) -out:$@ $^
-
-$(ODIR)/turbojpegl-dll.obj: turbojpegl.c
-	$(CC) $(CFLAGS) $(LIBCSTATIC) -DDLLDEFINE -c $< -Fo$@
-
-$(ODIR)/turbojpeg.dll $(ODIR)/turbojpeg.lib: $(ODIR)/turbojpegl-dll.obj \
-	$(LOBJSSTATIC)
-	$(LINK) $(LDFLAGS) -dll -out:$(ODIR)/turbojpeg.dll \
-		-implib:$(ODIR)/turbojpeg.lib $^
-
-
-$(ODIR)/jpgtest.exe: $(ODIR)/jpgtest.obj $(ODIR)/bmp-static.obj \
-	$(ODIR)/turbojpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-$(ODIR)/jpegut.exe: $(ODIR)/jpegut.obj $(ODIR)/turbojpeg.lib
-	$(LINK) $(LDFLAGS) -out:$@ $^
-
-
-ifeq ($(WIN64), yes)
-nsi: all
-	$(RM) $(ODIR)/libjpeg-turbo64.exe
-	makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo64 \
-		-DWLIBDIR=windows64 -DWSRCDIR=. -DWBLDDIR=windows64 -DWHDRDIR=win \
-		-DPLATFORM="Visual C++ 64-bit" -DWIN64 release/libjpeg-turbo.nsi
-else
-nsi: all
-	$(RM) $(ODIR)/libjpeg-turbo.exe
-	makensis -nocd -DVERSION=$(VERSION) -DAPPNAME=libjpeg-turbo \
-		-DWLIBDIR=windows -DWSRCDIR=. -DWBLDDIR=windows -DWHDRDIR=win \
-		-DPLATFORM="Visual C++" release/libjpeg-turbo.nsi
-endif
-
-test: testclean $(ODIR)/cjpeg.exe $(ODIR)/djpeg.exe $(ODIR)/jpegtran.exe \
-	$(ODIR)/jpegut.exe
-	cd $(ODIR);	./jpegut
-	$(ODIR)/cjpeg -dct int -outfile $(ODIR)/testoutint.jpg testorig.ppm
-	$(ODIR)/cjpeg -dct fast -opt -outfile $(ODIR)/testoutfst.jpg testorig.ppm
-	$(ODIR)/cjpeg -dct fast -quality 100 -opt -outfile $(ODIR)/testoutfst100.jpg testorig.ppm
-	$(ODIR)/cjpeg -dct float -outfile $(ODIR)/testoutflt.jpg testorig.ppm
-	cmp testimgint.jpg $(ODIR)/testoutint.jpg
-	cmp testimgfst.jpg $(ODIR)/testoutfst.jpg
-	cmp testimgfst100.jpg $(ODIR)/testoutfst100.jpg
-	cmp testimgflt.jpg $(ODIR)/testoutflt.jpg
-	$(ODIR)/djpeg -dct int -fast -ppm -outfile $(ODIR)/testoutint.ppm testorig.jpg
-	$(ODIR)/djpeg -dct fast -ppm -outfile $(ODIR)/testoutfst.ppm testorig.jpg
-	$(ODIR)/djpeg -dct float -ppm -outfile $(ODIR)/testoutflt.ppm testorig.jpg
-	cmp testimgint.ppm $(ODIR)/testoutint.ppm
-	cmp testimgfst.ppm $(ODIR)/testoutfst.ppm
-	cmp testimgflt.ppm $(ODIR)/testoutflt.ppm
-	$(ODIR)/djpeg -dct int -bmp -colors 256 -outfile $(ODIR)/testout.bmp  testorig.jpg
-	cmp testimg.bmp $(ODIR)/testout.bmp
-	$(ODIR)/cjpeg -dct int -progressive -outfile $(ODIR)/testoutp.jpg testorig.ppm
-	cmp testimgp.jpg $(ODIR)/testoutp.jpg
-	$(ODIR)/jpegtran -outfile $(ODIR)/testoutt.jpg $(ODIR)/testoutp.jpg
-	cmp testimgint.jpg $(ODIR)/testoutt.jpg
-
-testclean:
-	$(RM) $(ODIR)/testout* \
-	$(ODIR)/*_GRAYQ[0-9]*.bmp \
-	$(ODIR)/*_GRAYQ[0-9]*.ppm \
-	$(ODIR)/*_GRAYQ[0-9]*.jpg \
-	$(ODIR)/*_420Q[0-9]*.bmp \
-	$(ODIR)/*_420Q[0-9]*.ppm \
-	$(ODIR)/*_420Q[0-9]*.jpg \
-	$(ODIR)/*_422Q[0-9]*.bmp \
-	$(ODIR)/*_422Q[0-9]*.ppm \
-	$(ODIR)/*_422Q[0-9]*.jpg \
-	$(ODIR)/*_444Q[0-9]*.bmp \
-	$(ODIR)/*_444Q[0-9]*.ppm \
-	$(ODIR)/*_444Q[0-9]*.jpg
diff --git a/win/Makerules b/win/Makerules
deleted file mode 100755
index 51fba68..0000000
--- a/win/Makerules
+++ /dev/null
@@ -1,67 +0,0 @@
-ODIR = windows
-WIN64 = no
-ifeq ($(PROCESSOR_ARCHITECTURE), AMD64)
- WIN64 = yes
-else
- ifeq ($(PROCESSOR_ARCHITEW6432), AMD64)
-  WIN64 = yes
- endif
-endif
-ifeq ($(WIN64), yes)
-ODIR = windows64
-endif
-
-_DUMMY := $(shell mkdir -p $(ODIR))
-
-VERSION = 1.0.2
-
-CC = "cl" -nologo
-CXX = "cl" -EHsc -nologo
-AR = "link" -lib -nologo
-LINK = "link" -nologo
-ifeq ($(DEBUG), yes)
- LINK = "link" -nologo -debug
-endif
-ifeq ($(NASM),)
-NASM = nasm
-endif
-
-CFLAGS = -W3 -wd4996 -Iwin -I. -DBMP_SUPPORTED -DGIF_SUPPORTED \
-	-DPPM_SUPPORTED -DTARGA_SUPPORTED -DUSE_SETMODE
-ifeq ($(WIN64), yes)
-NAFLAGS = -fwin64 -DWIN64 -DMSVC -D__x86_64__ -Iwin/
-else
-NAFLAGS = -fwin32 -DWIN32 -DMSVC -Iwin/
-endif
-ifeq ($(DEBUG), yes)
- CFLAGS := $(CFLAGS) -Od -Zi
- NAFLAGS := $(NAFLAGS) -g
- LIBCDLL = -MDd
- LIBCSTATIC = -MTd
-else
- CFLAGS := $(CFLAGS) -O2
- LIBCDLL = -MD
- LIBCSTATIC = -MT
-endif
-
-WITH_SIMD = yes
-
-ifeq ($(WITH_SIMD), yes)
- CFLAGS := $(CFLAGS) -DWITH_SIMD
-endif
-
-
-$(ODIR)/%.obj: %.c
-	$(CC) $(CFLAGS) $(LIBCDLL) -c $< -Fo$@
-
-$(ODIR)/%-static.obj: %.c
-	$(CC) $(CFLAGS) $(LIBCSTATIC) -c $< -Fo$@
-
-$(ODIR)/%.obj: %.cxx
-	$(CXX) $(CXXFLAGS) $(LIBCSTATIC) -c $< -Fo$@
-
-$(ODIR)/%.obj: %.asm
-	$(NASM) $(NAFLAGS) -Isimd/ -o $@ $<
-
-$(ODIR)/%.lib: $(ODIR)/%.obj
-	$(AR) -out:$@ $<
diff --git a/win/config.h.in b/win/config.h.in
new file mode 100644
index 0000000..110af3c
--- /dev/null
+++ b/win/config.h.in
@@ -0,0 +1,3 @@
+#define VERSION "@VERSION@"

+#define BUILD "@BUILD@"

+#define PACKAGE_NAME "@CMAKE_PROJECT_NAME@"

diff --git a/win/jconfig.h b/win/jconfig.h.in
similarity index 86%
rename from win/jconfig.h
rename to win/jconfig.h.in
index a023455..3b835ea 100644
--- a/win/jconfig.h
+++ b/win/jconfig.h.in
@@ -1,5 +1,9 @@
 /* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */
-/* see jconfig.doc for explanations */
+/* see jconfig.txt for explanations */
+
+#define JPEG_LIB_VERSION @JPEG_LIB_VERSION@
+#cmakedefine C_ARITH_CODING_SUPPORTED
+#cmakedefine D_ARITH_CODING_SUPPORTED
 
 #define HAVE_PROTOTYPES
 #define HAVE_UNSIGNED_CHAR
diff --git a/win/jpeg.def b/win/jpeg62.def
similarity index 83%
rename from win/jpeg.def
rename to win/jpeg62.def
index 01d329f..3c33fbf 100755
--- a/win/jpeg.def
+++ b/win/jpeg62.def
@@ -1,103 +1,102 @@
-; h:\mingw\3.3.1\bin\dlltool.exe --output-def=jpeg.def jcapimin.o jcapistd.o jctrans.o jcparam.o jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o jccoefct.o jccolor.o jcsample.o jchuff.o jcphuff.o jcdctmgr.o jfdctfst.o jfdctflt.o jfdctint.o jdapimin.o jdapistd.o jdtrans.o jdatasrc.o jdmaster.o jdinput.o jdmarker.o jdhuff.o jdphuff.o jdmainct.o jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o jidctint.o jidctred.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o jcomapi.o jutils.o jerror.o jmemmgr.o jmemnobs.o jpeg-dllversion.o jpeg-dll-res.o

-EXPORTS

-	jcopy_block_row @ 1 ; 

-	jcopy_sample_rows @ 2 ; 

-	jdiv_round_up @ 3 ; 

-	jinit_1pass_quantizer @ 4 ; 

-	jinit_2pass_quantizer @ 5 ; 

-	jinit_c_coef_controller @ 6 ; 

-	jinit_c_main_controller @ 7 ; 

-	jinit_c_master_control @ 8 ; 

-	jinit_c_prep_controller @ 9 ; 

-	jinit_color_converter @ 10 ; 

-	jinit_color_deconverter @ 11 ; 

-	jinit_compress_master @ 12 ; 

-	jinit_d_coef_controller @ 13 ; 

-	jinit_d_main_controller @ 14 ; 

-	jinit_d_post_controller @ 15 ; 

-	jinit_downsampler @ 16 ; 

-	jinit_forward_dct @ 17 ; 

-	jinit_huff_decoder @ 18 ; 

-	jinit_huff_encoder @ 19 ; 

-	jinit_input_controller @ 20 ; 

-	jinit_inverse_dct @ 21 ; 

-	jinit_marker_reader @ 22 ; 

-	jinit_marker_writer @ 23 ; 

-	jinit_master_decompress @ 24 ; 

-	jinit_memory_mgr @ 25 ; 

-	jinit_merged_upsampler @ 26 ; 

-	jinit_phuff_decoder @ 27 ; 

-	jinit_phuff_encoder @ 28 ; 

-	jinit_upsampler @ 29 ; 

-	jpeg_CreateCompress @ 30 ; 

-	jpeg_CreateDecompress @ 31 ; 

-	jpeg_abort @ 32 ; 

-	jpeg_abort_compress @ 33 ; 

-	jpeg_abort_decompress @ 34 ; 

-	jpeg_add_quant_table @ 35 ; 

-	jpeg_alloc_huff_table @ 36 ; 

-	jpeg_alloc_quant_table @ 37 ; 

-	jpeg_calc_output_dimensions @ 38 ; 

-	jpeg_consume_input @ 39 ; 

-	jpeg_copy_critical_parameters @ 40 ; 

-	jpeg_default_colorspace @ 41 ; 

-	jpeg_destroy @ 42 ; 

-	jpeg_destroy_compress @ 43 ; 

-	jpeg_destroy_decompress @ 44 ; 

-	jpeg_fdct_float @ 45 ; 

-	jpeg_fdct_ifast @ 46 ; 

-	jpeg_fdct_islow @ 47 ; 

-	jpeg_fill_bit_buffer @ 48 ; 

-	jpeg_finish_compress @ 49 ; 

-	jpeg_finish_decompress @ 50 ; 

-	jpeg_finish_output @ 51 ; 

-	jpeg_free_large @ 52 ; 

-	jpeg_free_small @ 53 ; 

-	jpeg_gen_optimal_table @ 54 ; 

-	jpeg_get_large @ 55 ; 

-	jpeg_get_small @ 56 ; 

-	jpeg_has_multiple_scans @ 57 ; 

-	jpeg_huff_decode @ 58 ; 

-	jpeg_idct_1x1 @ 59 ; 

-	jpeg_idct_2x2 @ 60 ; 

-	jpeg_idct_4x4 @ 61 ; 

-	jpeg_idct_float @ 62 ; 

-	jpeg_idct_ifast @ 63 ; 

-	jpeg_idct_islow @ 64 ; 

-	jpeg_input_complete @ 65 ; 

-	jpeg_make_c_derived_tbl @ 66 ; 

-	jpeg_make_d_derived_tbl @ 67 ; 

-	jpeg_mem_available @ 68 ; 

-	jpeg_mem_init @ 69 ; 

-	jpeg_mem_term @ 70 ; 

-	jpeg_new_colormap @ 71 ; 

-	jpeg_open_backing_store @ 72 ; 

-	jpeg_quality_scaling @ 73 ; 

-	jpeg_read_coefficients @ 74 ; 

-	jpeg_read_header @ 75 ; 

-	jpeg_read_raw_data @ 76 ; 

-	jpeg_read_scanlines @ 77 ; 

-	jpeg_resync_to_restart @ 78 ; 

-	jpeg_save_markers @ 79 ; 

-	jpeg_set_colorspace @ 80 ; 

-	jpeg_set_defaults @ 81 ; 

-	jpeg_set_linear_quality @ 82 ; 

-	jpeg_set_marker_processor @ 83 ; 

-	jpeg_set_quality @ 84 ; 

-	jpeg_simple_progression @ 85 ; 

-	jpeg_start_compress @ 86 ; 

-	jpeg_start_decompress @ 87 ; 

-	jpeg_start_output @ 88 ; 

-	jpeg_std_error @ 89 ; 

-	jpeg_stdio_dest @ 90 ; 

-	jpeg_stdio_src @ 91 ; 

-	jpeg_suppress_tables @ 92 ; 

-	jpeg_write_coefficients @ 93 ; 

-	jpeg_write_m_byte @ 94 ; 

-	jpeg_write_m_header @ 95 ; 

-	jpeg_write_marker @ 96 ; 

-	jpeg_write_raw_data @ 97 ; 

-	jpeg_write_scanlines @ 98 ; 

-	jpeg_write_tables @ 99 ; 

-	jround_up @ 100 ; 

-	jzero_far @ 101 ; 

+EXPORTS
+	jcopy_block_row @ 1 ; 
+	jcopy_sample_rows @ 2 ; 
+	jdiv_round_up @ 3 ; 
+	jinit_1pass_quantizer @ 4 ; 
+	jinit_2pass_quantizer @ 5 ; 
+	jinit_c_coef_controller @ 6 ; 
+	jinit_c_main_controller @ 7 ; 
+	jinit_c_master_control @ 8 ; 
+	jinit_c_prep_controller @ 9 ; 
+	jinit_color_converter @ 10 ; 
+	jinit_color_deconverter @ 11 ; 
+	jinit_compress_master @ 12 ; 
+	jinit_d_coef_controller @ 13 ; 
+	jinit_d_main_controller @ 14 ; 
+	jinit_d_post_controller @ 15 ; 
+	jinit_downsampler @ 16 ; 
+	jinit_forward_dct @ 17 ; 
+	jinit_huff_decoder @ 18 ; 
+	jinit_huff_encoder @ 19 ; 
+	jinit_input_controller @ 20 ; 
+	jinit_inverse_dct @ 21 ; 
+	jinit_marker_reader @ 22 ; 
+	jinit_marker_writer @ 23 ; 
+	jinit_master_decompress @ 24 ; 
+	jinit_memory_mgr @ 25 ; 
+	jinit_merged_upsampler @ 26 ; 
+	jinit_phuff_decoder @ 27 ; 
+	jinit_phuff_encoder @ 28 ; 
+	jinit_upsampler @ 29 ; 
+	jpeg_CreateCompress @ 30 ; 
+	jpeg_CreateDecompress @ 31 ; 
+	jpeg_abort @ 32 ; 
+	jpeg_abort_compress @ 33 ; 
+	jpeg_abort_decompress @ 34 ; 
+	jpeg_add_quant_table @ 35 ; 
+	jpeg_alloc_huff_table @ 36 ; 
+	jpeg_alloc_quant_table @ 37 ; 
+	jpeg_calc_output_dimensions @ 38 ; 
+	jpeg_consume_input @ 39 ; 
+	jpeg_copy_critical_parameters @ 40 ; 
+	jpeg_default_colorspace @ 41 ; 
+	jpeg_destroy @ 42 ; 
+	jpeg_destroy_compress @ 43 ; 
+	jpeg_destroy_decompress @ 44 ; 
+	jpeg_fdct_float @ 45 ; 
+	jpeg_fdct_ifast @ 46 ; 
+	jpeg_fdct_islow @ 47 ; 
+	jpeg_fill_bit_buffer @ 48 ; 
+	jpeg_finish_compress @ 49 ; 
+	jpeg_finish_decompress @ 50 ; 
+	jpeg_finish_output @ 51 ; 
+	jpeg_free_large @ 52 ; 
+	jpeg_free_small @ 53 ; 
+	jpeg_gen_optimal_table @ 54 ; 
+	jpeg_get_large @ 55 ; 
+	jpeg_get_small @ 56 ; 
+	jpeg_has_multiple_scans @ 57 ; 
+	jpeg_huff_decode @ 58 ; 
+	jpeg_idct_1x1 @ 59 ; 
+	jpeg_idct_2x2 @ 60 ; 
+	jpeg_idct_4x4 @ 61 ; 
+	jpeg_idct_float @ 62 ; 
+	jpeg_idct_ifast @ 63 ; 
+	jpeg_idct_islow @ 64 ; 
+	jpeg_input_complete @ 65 ; 
+	jpeg_make_c_derived_tbl @ 66 ; 
+	jpeg_make_d_derived_tbl @ 67 ; 
+	jpeg_mem_available @ 68 ; 
+	jpeg_mem_init @ 69 ; 
+	jpeg_mem_term @ 70 ; 
+	jpeg_new_colormap @ 71 ; 
+	jpeg_open_backing_store @ 72 ; 
+	jpeg_quality_scaling @ 73 ; 
+	jpeg_read_coefficients @ 74 ; 
+	jpeg_read_header @ 75 ; 
+	jpeg_read_raw_data @ 76 ; 
+	jpeg_read_scanlines @ 77 ; 
+	jpeg_resync_to_restart @ 78 ; 
+	jpeg_save_markers @ 79 ; 
+	jpeg_set_colorspace @ 80 ; 
+	jpeg_set_defaults @ 81 ; 
+	jpeg_set_linear_quality @ 82 ; 
+	jpeg_set_marker_processor @ 83 ; 
+	jpeg_set_quality @ 84 ; 
+	jpeg_simple_progression @ 85 ; 
+	jpeg_start_compress @ 86 ; 
+	jpeg_start_decompress @ 87 ; 
+	jpeg_start_output @ 88 ; 
+	jpeg_std_error @ 89 ; 
+	jpeg_stdio_dest @ 90 ; 
+	jpeg_stdio_src @ 91 ; 
+	jpeg_suppress_tables @ 92 ; 
+	jpeg_write_coefficients @ 93 ; 
+	jpeg_write_m_byte @ 94 ; 
+	jpeg_write_m_header @ 95 ; 
+	jpeg_write_marker @ 96 ; 
+	jpeg_write_raw_data @ 97 ; 
+	jpeg_write_scanlines @ 98 ; 
+	jpeg_write_tables @ 99 ; 
+	jround_up @ 100 ; 
+	jzero_far @ 101 ; 
diff --git a/win/jpeg7.def b/win/jpeg7.def
new file mode 100644
index 0000000..5ca227b
--- /dev/null
+++ b/win/jpeg7.def
@@ -0,0 +1,104 @@
+EXPORTS
+	jcopy_block_row @ 1 ; 
+	jcopy_sample_rows @ 2 ; 
+	jdiv_round_up @ 3 ; 
+	jinit_1pass_quantizer @ 4 ; 
+	jinit_2pass_quantizer @ 5 ; 
+	jinit_c_coef_controller @ 6 ; 
+	jinit_c_main_controller @ 7 ; 
+	jinit_c_master_control @ 8 ; 
+	jinit_c_prep_controller @ 9 ; 
+	jinit_color_converter @ 10 ; 
+	jinit_color_deconverter @ 11 ; 
+	jinit_compress_master @ 12 ; 
+	jinit_d_coef_controller @ 13 ; 
+	jinit_d_main_controller @ 14 ; 
+	jinit_d_post_controller @ 15 ; 
+	jinit_downsampler @ 16 ; 
+	jinit_forward_dct @ 17 ; 
+	jinit_huff_decoder @ 18 ; 
+	jinit_huff_encoder @ 19 ; 
+	jinit_input_controller @ 20 ; 
+	jinit_inverse_dct @ 21 ; 
+	jinit_marker_reader @ 22 ; 
+	jinit_marker_writer @ 23 ; 
+	jinit_master_decompress @ 24 ; 
+	jinit_memory_mgr @ 25 ; 
+	jinit_merged_upsampler @ 26 ; 
+	jinit_phuff_decoder @ 27 ; 
+	jinit_phuff_encoder @ 28 ; 
+	jinit_upsampler @ 29 ; 
+	jpeg_CreateCompress @ 30 ; 
+	jpeg_CreateDecompress @ 31 ; 
+	jpeg_abort @ 32 ; 
+	jpeg_abort_compress @ 33 ; 
+	jpeg_abort_decompress @ 34 ; 
+	jpeg_add_quant_table @ 35 ; 
+	jpeg_alloc_huff_table @ 36 ; 
+	jpeg_alloc_quant_table @ 37 ; 
+	jpeg_calc_jpeg_dimensions @ 38 ; 
+	jpeg_calc_output_dimensions @ 39 ; 
+	jpeg_consume_input @ 40 ; 
+	jpeg_copy_critical_parameters @ 41 ; 
+	jpeg_default_colorspace @ 42 ; 
+	jpeg_default_qtables @ 43 ;
+	jpeg_destroy @ 44 ; 
+	jpeg_destroy_compress @ 45 ; 
+	jpeg_destroy_decompress @ 46 ; 
+	jpeg_fdct_float @ 47 ; 
+	jpeg_fdct_ifast @ 48 ; 
+	jpeg_fdct_islow @ 49 ; 
+	jpeg_fill_bit_buffer @ 50 ; 
+	jpeg_finish_compress @ 51 ; 
+	jpeg_finish_decompress @ 52 ; 
+	jpeg_finish_output @ 53 ; 
+	jpeg_free_large @ 54 ; 
+	jpeg_free_small @ 55 ; 
+	jpeg_gen_optimal_table @ 56 ; 
+	jpeg_get_large @ 57 ; 
+	jpeg_get_small @ 58 ; 
+	jpeg_has_multiple_scans @ 59 ; 
+	jpeg_huff_decode @ 60 ; 
+	jpeg_idct_1x1 @ 61 ; 
+	jpeg_idct_2x2 @ 62 ; 
+	jpeg_idct_4x4 @ 63 ; 
+	jpeg_idct_float @ 64 ; 
+	jpeg_idct_ifast @ 65 ; 
+	jpeg_idct_islow @ 66 ; 
+	jpeg_input_complete @ 67 ; 
+	jpeg_make_c_derived_tbl @ 68 ; 
+	jpeg_make_d_derived_tbl @ 69 ; 
+	jpeg_mem_available @ 70 ; 
+	jpeg_mem_init @ 71 ; 
+	jpeg_mem_term @ 72 ; 
+	jpeg_new_colormap @ 73 ; 
+	jpeg_open_backing_store @ 74 ; 
+	jpeg_quality_scaling @ 75 ; 
+	jpeg_read_coefficients @ 76 ; 
+	jpeg_read_header @ 77 ; 
+	jpeg_read_raw_data @ 78 ; 
+	jpeg_read_scanlines @ 79 ; 
+	jpeg_resync_to_restart @ 80 ; 
+	jpeg_save_markers @ 81 ; 
+	jpeg_set_colorspace @ 82 ; 
+	jpeg_set_defaults @ 83 ; 
+	jpeg_set_linear_quality @ 84 ; 
+	jpeg_set_marker_processor @ 85 ; 
+	jpeg_set_quality @ 86 ; 
+	jpeg_simple_progression @ 87 ; 
+	jpeg_start_compress @ 88 ; 
+	jpeg_start_decompress @ 89 ; 
+	jpeg_start_output @ 90 ; 
+	jpeg_std_error @ 91 ; 
+	jpeg_stdio_dest @ 92 ; 
+	jpeg_stdio_src @ 93 ; 
+	jpeg_suppress_tables @ 94 ; 
+	jpeg_write_coefficients @ 95 ; 
+	jpeg_write_m_byte @ 96 ; 
+	jpeg_write_m_header @ 97 ; 
+	jpeg_write_marker @ 98 ; 
+	jpeg_write_raw_data @ 99 ; 
+	jpeg_write_scanlines @ 100 ; 
+	jpeg_write_tables @ 101 ; 
+	jround_up @ 102 ; 
+	jzero_far @ 103 ; 
diff --git a/win/jpeg8.def b/win/jpeg8.def
new file mode 100644
index 0000000..3fa6111
--- /dev/null
+++ b/win/jpeg8.def
@@ -0,0 +1,107 @@
+EXPORTS
+	jcopy_block_row @ 1 ; 
+	jcopy_sample_rows @ 2 ; 
+	jdiv_round_up @ 3 ; 
+	jinit_1pass_quantizer @ 4 ; 
+	jinit_2pass_quantizer @ 5 ; 
+	jinit_c_coef_controller @ 6 ; 
+	jinit_c_main_controller @ 7 ; 
+	jinit_c_master_control @ 8 ; 
+	jinit_c_prep_controller @ 9 ; 
+	jinit_color_converter @ 10 ; 
+	jinit_color_deconverter @ 11 ; 
+	jinit_compress_master @ 12 ; 
+	jinit_d_coef_controller @ 13 ; 
+	jinit_d_main_controller @ 14 ; 
+	jinit_d_post_controller @ 15 ; 
+	jinit_downsampler @ 16 ; 
+	jinit_forward_dct @ 17 ; 
+	jinit_huff_decoder @ 18 ; 
+	jinit_huff_encoder @ 19 ; 
+	jinit_input_controller @ 20 ; 
+	jinit_inverse_dct @ 21 ; 
+	jinit_marker_reader @ 22 ; 
+	jinit_marker_writer @ 23 ; 
+	jinit_master_decompress @ 24 ; 
+	jinit_memory_mgr @ 25 ; 
+	jinit_merged_upsampler @ 26 ; 
+	jinit_phuff_decoder @ 27 ; 
+	jinit_phuff_encoder @ 28 ; 
+	jinit_upsampler @ 29 ; 
+	jpeg_CreateCompress @ 30 ; 
+	jpeg_CreateDecompress @ 31 ; 
+	jpeg_abort @ 32 ; 
+	jpeg_abort_compress @ 33 ; 
+	jpeg_abort_decompress @ 34 ; 
+	jpeg_add_quant_table @ 35 ; 
+	jpeg_alloc_huff_table @ 36 ; 
+	jpeg_alloc_quant_table @ 37 ; 
+	jpeg_calc_jpeg_dimensions @ 38 ; 
+	jpeg_calc_output_dimensions @ 39 ; 
+	jpeg_consume_input @ 40 ; 
+	jpeg_copy_critical_parameters @ 41 ; 
+	jpeg_core_output_dimensions @ 42 ; 
+	jpeg_default_colorspace @ 43 ; 
+	jpeg_default_qtables @ 44 ;
+	jpeg_destroy @ 45 ; 
+	jpeg_destroy_compress @ 46 ; 
+	jpeg_destroy_decompress @ 47 ; 
+	jpeg_fdct_float @ 48 ; 
+	jpeg_fdct_ifast @ 49 ; 
+	jpeg_fdct_islow @ 50 ; 
+	jpeg_fill_bit_buffer @ 51 ; 
+	jpeg_finish_compress @ 52 ; 
+	jpeg_finish_decompress @ 53 ; 
+	jpeg_finish_output @ 54 ; 
+	jpeg_free_large @ 55 ; 
+	jpeg_free_small @ 56 ; 
+	jpeg_gen_optimal_table @ 57 ; 
+	jpeg_get_large @ 58 ; 
+	jpeg_get_small @ 59 ; 
+	jpeg_has_multiple_scans @ 60 ; 
+	jpeg_huff_decode @ 61 ; 
+	jpeg_idct_1x1 @ 62 ; 
+	jpeg_idct_2x2 @ 63 ; 
+	jpeg_idct_4x4 @ 64 ; 
+	jpeg_idct_float @ 65 ; 
+	jpeg_idct_ifast @ 66 ; 
+	jpeg_idct_islow @ 67 ; 
+	jpeg_input_complete @ 68 ; 
+	jpeg_make_c_derived_tbl @ 69 ; 
+	jpeg_make_d_derived_tbl @ 70 ; 
+	jpeg_mem_available @ 71 ; 
+	jpeg_mem_dest @ 72 ;
+	jpeg_mem_init @ 73 ; 
+	jpeg_mem_src @ 74 ;
+	jpeg_mem_term @ 75 ; 
+	jpeg_new_colormap @ 76 ; 
+	jpeg_open_backing_store @ 77 ; 
+	jpeg_quality_scaling @ 78 ; 
+	jpeg_read_coefficients @ 79 ; 
+	jpeg_read_header @ 80 ; 
+	jpeg_read_raw_data @ 81 ; 
+	jpeg_read_scanlines @ 82 ; 
+	jpeg_resync_to_restart @ 83 ; 
+	jpeg_save_markers @ 84 ; 
+	jpeg_set_colorspace @ 85 ; 
+	jpeg_set_defaults @ 86 ; 
+	jpeg_set_linear_quality @ 87 ; 
+	jpeg_set_marker_processor @ 88 ; 
+	jpeg_set_quality @ 89 ; 
+	jpeg_simple_progression @ 90 ; 
+	jpeg_start_compress @ 91 ; 
+	jpeg_start_decompress @ 92 ; 
+	jpeg_start_output @ 93 ; 
+	jpeg_std_error @ 94 ; 
+	jpeg_stdio_dest @ 95 ; 
+	jpeg_stdio_src @ 96 ; 
+	jpeg_suppress_tables @ 97 ; 
+	jpeg_write_coefficients @ 98 ; 
+	jpeg_write_m_byte @ 99 ; 
+	jpeg_write_m_header @ 100 ; 
+	jpeg_write_marker @ 101 ; 
+	jpeg_write_raw_data @ 102 ; 
+	jpeg_write_scanlines @ 103 ; 
+	jpeg_write_tables @ 104 ; 
+	jround_up @ 105 ; 
+	jzero_far @ 106 ; 
diff --git a/wizard.doc b/wizard.txt
similarity index 100%
rename from wizard.doc
rename to wizard.txt
diff --git a/wrppm.c b/wrppm.c
index 6c6d908..68e0c85 100644
--- a/wrppm.c
+++ b/wrppm.c
@@ -2,6 +2,7 @@
  * wrppm.c
  *
  * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -40,11 +41,11 @@
 #define BYTESPERSAMPLE 1
 #define PPM_MAXVAL 255
 #else
-/* The word-per-sample format always puts the LSB first. */
+/* The word-per-sample format always puts the MSB first. */
 #define PUTPPMSAMPLE(ptr,v)			\
 	{ register int val_ = v;		\
-	  *ptr++ = (char) (val_ & 0xFF);	\
 	  *ptr++ = (char) ((val_ >> 8) & 0xFF);	\
+	  *ptr++ = (char) (val_ & 0xFF);	\
 	}
 #define BYTESPERSAMPLE 2
 #define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1)