Add a Java version of TJBench and extend the TurboJPEG Java API to support it (this involved adding a polymorphic method in TJCompressor that accepts x and y offsets into a larger buffer, similar to the previous modification that had been done to TJDecompressor.)


git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@862 632fc199-4ca6-4c93-a231-07263d6284db
diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt
index 87f8ec6..87db412 100644
--- a/java/CMakeLists.txt
+++ b/java/CMakeLists.txt
@@ -9,7 +9,8 @@
   org/libjpegturbo/turbojpeg/TJTransform
   org/libjpegturbo/turbojpeg/TJTransformer
   TJUnitTest
-  TJExample)
+  TJExample
+  TJBench)
 
 if(MSVC_IDE)
   set(OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/$(OutDir)")
diff --git a/java/Makefile.am b/java/Makefile.am
index 4a1b34e..6896fa2 100644
--- a/java/Makefile.am
+++ b/java/Makefile.am
@@ -9,7 +9,8 @@
 	org/libjpegturbo/turbojpeg/TJTransform.java \
 	org/libjpegturbo/turbojpeg/TJTransformer.java \
 	TJExample.java \
-	TJUnitTest.java
+	TJUnitTest.java \
+	TJBench.java
 
 JNIHEADERS = org_libjpegturbo_turbojpeg_TJ.h \
 	org_libjpegturbo_turbojpeg_TJCompressor.h \
@@ -29,7 +30,8 @@
 	org/libjpegturbo/turbojpeg/TJTransform.class \
 	org/libjpegturbo/turbojpeg/TJTransformer.class \
 	TJExample.class \
-	TJUnitTest.class
+	TJUnitTest.class \
+	TJBench.class
 
 all: all-am turbojpeg.jar
 
diff --git a/java/TJBench.java b/java/TJBench.java
new file mode 100644
index 0000000..2f27b8e
--- /dev/null
+++ b/java/TJBench.java
@@ -0,0 +1,863 @@
+/*
+ * Copyright (C)2009-2012 D. R. Commander.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the libjpeg-turbo Project nor the names of its
+ *   contributors may be used to endorse or promote products derived from this
+ *   software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.io.*;
+import java.awt.image.*;
+import javax.imageio.*;
+import java.util.*;
+import org.libjpegturbo.turbojpeg.*;
+
+class TJBench
+{
+  static final int YUVENCODE = 1;
+  static final int YUVDECODE = 2;
+
+  static int flags = 0, yuv = 0, quiet = 0, pf = TJ.PF_BGR;
+  static boolean decompOnly, doTile;
+
+  static final String pixFormatStr[] = {
+    "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY"
+  };
+
+  static final String subNameLong[] = {
+    "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
+  };
+
+  static final String subName[] = {
+    "444", "422", "420", "GRAY", "440"
+  };
+
+  static TJScalingFactor sf;
+  static int nsf = 0;
+  static int xformOp = TJTransform.OP_NONE, xformOpt = 0;
+  static double benchTime = 5.0;
+
+
+  static final double getTime()
+  {
+    return (double)System.nanoTime() / 1.0e9;
+  }
+
+
+  static String sigFig(double val, int figs)
+  {
+    String format;
+    int digitsAfterDecimal = figs - (int)Math.ceil(Math.log10(Math.abs(val)));
+    if (digitsAfterDecimal < 1)
+      format = new String("%.0f");
+    else
+      format = new String("%." + digitsAfterDecimal + "f");
+    return String.format(format, val);
+  }
+
+
+  static byte[] loadImage(String fileName, int[] w, int[] h, int pf)
+                          throws Exception
+  {
+    BufferedImage img = ImageIO.read(new File(fileName));
+    if (img == null)
+      throw new Exception("Could not read " + fileName);
+    w[0] = img.getWidth();
+    h[0] = img.getHeight();
+    int rgb[] = img.getRGB(0, 0, w[0], h[0], null, 0, w[0]);
+    int ps = TJ.getPixelSize(pf);
+    int rindex = TJ.getRedOffset(pf);
+    int gindex = TJ.getGreenOffset(pf);
+    int bindex = TJ.getBlueOffset(pf);
+    byte[] dstBuf = new byte[w[0] * h[0] * ps];
+    int pixels = w[0] * h[0], dstPtr = 0, rgbPtr = 0;
+    while (pixels-- > 0) {
+      dstBuf[dstPtr + rindex] = (byte)((rgb[rgbPtr] >> 16) & 0xff);
+      dstBuf[dstPtr + gindex] = (byte)((rgb[rgbPtr] >> 8) & 0xff);
+      dstBuf[dstPtr + bindex] = (byte)(rgb[rgbPtr] & 0xff);
+      dstPtr += ps;
+      rgbPtr++;
+    }
+    return dstBuf;
+  }
+
+
+  static void saveImage(String fileName, byte[] srcBuf, int w, int h, int pf)
+    throws Exception
+  {
+    BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+    int pixels = w * h, srcPtr = 0;
+    int ps = TJ.getPixelSize(pf);
+    int rindex = TJ.getRedOffset(pf);
+    int gindex = TJ.getGreenOffset(pf);
+    int bindex = TJ.getBlueOffset(pf);
+    for (int y = 0; y < h; y++) {
+      for (int x = 0; x < w; x++, srcPtr += ps) {
+        int pixel = (srcBuf[srcPtr + rindex] & 0xff) << 16 |
+                    (srcBuf[srcPtr + gindex] & 0xff) << 8 |
+                    (srcBuf[srcPtr + bindex] & 0xff);
+        img.setRGB(x, y, pixel);
+      }
+    }
+    ImageIO.write(img, "bmp", new File(fileName));
+  }
+
+
+  /* Decompression test */
+  static void decompTest(byte[] srcBuf, byte[][] jpegBuf, int[] jpegSize,
+                         byte[] dstBuf, int w, int h, int subsamp,
+                         int jpegQual, String fileName, int tilew, int tileh)
+                         throws Exception
+  {
+    String qualStr = new String(""), sizeStr, tempStr;
+    TJDecompressor tjd;
+    double start, elapsed;
+    int ps = TJ.getPixelSize(pf), i;
+    int yuvSize = TJ.bufSizeYUV(w, h, subsamp), bufsize;
+    int scaledw = (yuv == YUVDECODE) ? w : sf.getScaled(w);
+    int scaledh = (yuv == YUVDECODE) ? h : sf.getScaled(h);
+    int pitch = scaledw * ps;
+  
+    if (jpegQual > 0)
+      qualStr = new String("_Q" + jpegQual);
+  
+    tjd = new TJDecompressor();
+  
+    int bufSize = (yuv == YUVDECODE ? yuvSize : pitch * scaledh);
+    if (dstBuf == null)
+      dstBuf = new byte[bufSize];
+
+    /* Set the destination buffer to gray so we know whether the decompressor
+       attempted to write to it */
+    Arrays.fill(dstBuf, (byte)127);
+  
+    /* Execute once to preload cache */
+    tjd.setJPEGImage(jpegBuf[0], jpegSize[0]);
+    if (yuv == YUVDECODE)
+      tjd.decompressToYUV(dstBuf, flags);
+    else
+      tjd.decompress(dstBuf, scaledw, pitch, scaledh, pf, flags);
+  
+    /* Benchmark */
+    for (i = 0, start = getTime(); (elapsed = getTime() - start) < benchTime;
+         i++) {
+      int tile=0;
+      if (yuv == YUVDECODE)
+        tjd.decompressToYUV(dstBuf, flags);
+      else {
+        for (int y = 0; y < h; y += tileh) {
+          for (int x = 0; x < w; x += tilew, tile++) {
+            int width = doTile ? Math.min(tilew, w - x) : scaledw;
+            int height = doTile ? Math.min(tileh, h - y) : scaledh;
+            tjd.setJPEGImage(jpegBuf[tile], jpegSize[tile]);
+            tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags);
+          }
+        }
+      }
+    }
+
+    tjd = null;
+    System.gc();
+
+    if (quiet != 0)
+      System.out.println(
+        sigFig((double)(w * h) / 1000000. * (double)i / elapsed, 4));
+    else {
+      System.out.format("D--> Frame rate:           %f fps\n",
+                        (double)i / elapsed);
+      System.out.format("     Dest. throughput:     %f Megapixels/sec\n",
+                        (double)(w * h) / 1000000. * (double)i / elapsed);
+    }
+  
+    if (yuv == YUVDECODE) {
+      tempStr = fileName + "_" + subName[subsamp] + qualStr + ".yuv";
+      FileOutputStream fos = new FileOutputStream(tempStr);
+      fos.write(dstBuf, 0, yuvSize);
+      fos.close();
+    } else {
+      if (sf.getNum() != 1 || sf.getDenom() != 1)
+        sizeStr = new String(sf.getNum() + "_" + sf.getDenom());
+      else if (tilew != w || tileh != h)
+        sizeStr = new String(tilew + "x" + tileh);
+      else
+        sizeStr = new String("full");
+      if (decompOnly)
+        tempStr = new String(fileName + "_" + sizeStr + ".bmp");
+      else
+        tempStr = new String(fileName + "_" + subName[subsamp] + qualStr +
+                             "_" + sizeStr + ".bmp");
+      saveImage(tempStr, dstBuf, scaledw, scaledh, pf);
+      int ndx = tempStr.indexOf('.');
+      tempStr = new String(tempStr.substring(0, ndx) + "-err.bmp");
+      if (srcBuf != null && sf.getNum() == 1 && sf.getDenom() == 1) {
+        if (quiet == 0)
+          System.out.println("Compression error written to " + tempStr + ".");
+        if (subsamp == TJ.SAMP_GRAY) {
+          for (int y = 0, index = 0; y < h; y++, index += pitch) {
+            for (int x = 0, index2 = index; x < w; x++, index2 += ps) {
+              int rindex = index2 + TJ.getRedOffset(pf);
+              int gindex = index2 + TJ.getGreenOffset(pf);
+              int bindex = index2 + TJ.getBlueOffset(pf);
+              int lum = (int)((double)(srcBuf[rindex] & 0xff) * 0.299 +
+                              (double)(srcBuf[gindex] & 0xff) * 0.587 +
+                              (double)(srcBuf[bindex] & 0xff) * 0.114 + 0.5);
+              if (lum > 255) lum = 255;  if (lum < 0) lum = 0;
+              dstBuf[rindex] = (byte)Math.abs((dstBuf[rindex] & 0xff) - lum);
+              dstBuf[gindex] = (byte)Math.abs((dstBuf[gindex] & 0xff) - lum);
+              dstBuf[bindex] = (byte)Math.abs((dstBuf[bindex] & 0xff) - lum);
+            }
+          }
+        } else {
+          for (int y = 0; y < h; y++)
+            for (int x = 0; x < w * ps; x++)
+              dstBuf[pitch * y + x] =
+                (byte)Math.abs((dstBuf[pitch * y + x] & 0xff) -
+                               (srcBuf[pitch * y + x] & 0xff));
+        }
+        saveImage(tempStr, dstBuf, w, h, pf);
+      }
+    }
+  }
+
+
+  static void doTestYUV(byte[] srcBuf, int w, int h, int subsamp,
+                        String fileName) throws Exception
+  {
+    TJCompressor tjc;
+    byte[] dstBuf;
+    double start, elapsed;
+    int ps = TJ.getPixelSize(pf), i;
+    int yuvSize = 0;
+  
+    yuvSize = TJ.bufSizeYUV(w, h, subsamp);
+    dstBuf = new byte[yuvSize];
+  
+    if (quiet == 0)
+      System.out.format(">>>>>  %s (%s) <--> YUV %s  <<<<<\n",
+        pixFormatStr[pf],
+        (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down",
+        subNameLong[subsamp]);
+  
+    if (quiet == 1)
+      System.out.format("%s\t%s\t%s\tN/A\t", pixFormatStr[pf],
+                        (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD",
+                        subNameLong[subsamp]);
+  
+    tjc = new TJCompressor(srcBuf, w, 0, h, pf);
+    tjc.setSubsamp(subsamp);
+  
+    /* Execute once to preload cache */
+    tjc.encodeYUV(dstBuf, flags);
+  
+    /* Benchmark */
+    for (i = 0, start = getTime();
+         (elapsed = getTime() - start) < benchTime; i++)
+      tjc.encodeYUV(dstBuf, flags);
+  
+    if (quiet == 1)
+      System.out.format("%-4d  %-4d\t", w, h);
+    if (quiet != 0) {
+      System.out.format("%s%c%s%c",
+        sigFig((double)(w * h) / 1000000. * (double) i / elapsed, 4),
+        quiet == 2 ? '\n' : '\t',
+        sigFig((double)(w * h * ps) / (double)yuvSize, 4),
+        quiet == 2 ? '\n' : '\t');
+    } else {
+      System.out.format("\n%s size: %d x %d\n", "Image", w, h);
+      System.out.format("C--> Frame rate:           %f fps\n",
+                        (double)i / elapsed);
+      System.out.format("     Output image size:    %d bytes\n", yuvSize);
+      System.out.format("     Compression ratio:    %f:1\n",
+                        (double)(w * h * ps) / (double)yuvSize);
+      System.out.format("     Source throughput:    %f Megapixels/sec\n",
+                        (double)(w * h) / 1000000. * (double)i / elapsed);
+      System.out.format("     Output bit stream:    %f Megabits/sec\n",
+                        (double)yuvSize * 8. / 1000000. * (double)i / elapsed);
+    }
+    String tempStr = fileName + "_" + subName[subsamp] + ".yuv";
+    FileOutputStream fos = new FileOutputStream(tempStr);
+    fos.write(dstBuf, 0, yuvSize);
+    fos.close();
+    if (quiet == 0)
+      System.out.println("Reference image written to " + tempStr);
+  }
+  
+
+  static void doTest(byte[] srcBuf, int w, int h, int subsamp, int jpegQual,
+                     String fileName) throws Exception
+  {
+    TJCompressor tjc;
+    byte[] tmpBuf;
+    byte[][] jpegBuf;
+    int[] jpegSize;
+    double start, elapsed;
+    int totalJpegSize = 0, tilew, tileh, i;
+    int ps = TJ.getPixelSize(pf), ntilesw = 1, ntilesh = 1, pitch = w * ps;
+  
+    if (yuv == YUVENCODE) {
+      doTestYUV(srcBuf, w, h, subsamp, fileName);
+      return;
+    }
+ 
+    tmpBuf = new byte[pitch * h];
+
+    if (quiet == 0)
+      System.out.format(">>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n",
+        pixFormatStr[pf],
+        (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down",
+        subNameLong[subsamp], jpegQual);
+
+    tjc = new TJCompressor();
+  
+    for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
+         tilew *= 2, tileh *= 2) {
+      if (tilew > w)
+        tilew = w;
+      if (tileh > h)
+        tileh = h;
+      ntilesw = (w + tilew - 1) / tilew;
+      ntilesh = (h + tileh - 1) / tileh;
+
+      jpegBuf = new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)];
+      jpegSize = new int[ntilesw * ntilesh];
+  
+      /* Compression test */
+      if (quiet == 1)
+        System.out.format("%s\t%s\t%s\t%d\t", pixFormatStr[pf],
+                          (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD",
+                          subNameLong[subsamp], jpegQual);
+      for (i = 0; i < h; i++)
+        System.arraycopy(srcBuf, w * ps * i, tmpBuf, pitch * i, w * ps);
+      tjc.setSourceImage(srcBuf, tilew, pitch, tileh, pf);
+      tjc.setJPEGQuality(jpegQual);
+      tjc.setSubsamp(subsamp);
+
+      /* Execute once to preload cache */
+      tjc.compress(jpegBuf[0], flags);
+  
+      /* Benchmark */
+      for (i = 0, start = getTime();
+           (elapsed = getTime() - start) < benchTime; i++) {
+        int tile = 0;
+        totalJpegSize = 0;
+        for (int y = 0; y < h; y += tileh) {
+          for (int x = 0; x < w; x += tilew, tile++) {
+            int width = Math.min(tilew, w - x);
+            int height = Math.min(tileh, h - y);
+            tjc.setSourceImage(srcBuf, x, y, width, pitch, height, pf);
+            tjc.compress(jpegBuf[tile], flags);
+            jpegSize[tile] = tjc.getCompressedSize();
+            totalJpegSize += jpegSize[tile];
+          }
+        }
+      }
+
+      if (quiet == 1)
+        System.out.format("%-4d  %-4d\t", tilew, tileh);
+      if (quiet != 0) {
+        System.out.format("%s%c%s%c",
+          sigFig((double)(w * h) / 1000000. * (double) i / elapsed, 4),
+          quiet == 2 ? '\n' : '\t',
+          sigFig((double)(w * h * ps) / (double)totalJpegSize, 4),
+          quiet == 2 ? '\n' : '\t');
+      } else {
+        System.out.format("\n%s size: %d x %d\n", doTile ? "Tile" : "Image",
+                          tilew, tileh);
+        System.out.format("C--> Frame rate:           %f fps\n",
+                          (double)i / elapsed);
+        System.out.format("     Output image size:    %d bytes\n",
+                          totalJpegSize);
+        System.out.format("     Compression ratio:    %f:1\n",
+                          (double)(w * h * ps) / (double)totalJpegSize);
+        System.out.format("     Source throughput:    %f Megapixels/sec\n",
+                          (double)(w * h) / 1000000. * (double)i / elapsed);
+        System.out.format("     Output bit stream:    %f Megabits/sec\n",
+          (double)totalJpegSize * 8. / 1000000. * (double)i / elapsed);
+      }
+      if (tilew == w && tileh == h) {
+        String tempStr = fileName + "_" + subName[subsamp] + "_" + "Q" +
+                         jpegQual + ".jpg";
+        FileOutputStream fos = new FileOutputStream(tempStr);
+        fos.write(jpegBuf[0], 0, jpegSize[0]);
+        fos.close();
+        if (quiet == 0)
+          System.out.println("Reference image written to " + tempStr);
+      }
+  
+      /* Decompression test */
+      decompTest(srcBuf, jpegBuf, jpegSize, tmpBuf, w, h, subsamp, jpegQual,
+                 fileName, tilew, tileh);
+  
+      for (i = 0; i < ntilesw * ntilesh; i++)
+        jpegBuf[i] = null;
+      jpegBuf = null;  jpegSize = null;
+      System.gc();
+
+      if (tilew == w && tileh == h) break;
+    }
+  }
+
+
+  static void doDecompTest(String fileName) throws Exception
+  {
+    TJTransformer tjt;
+    byte[][] jpegBuf;
+    byte[] srcBuf;
+    int[] jpegSize;
+    int totalJpegSize;
+    int w = 0, h = 0, subsamp = -1, _w, _h, _tilew, _tileh,
+      _ntilesw, _ntilesh, _subsamp, x, y;
+    int ntilesw = 1, ntilesh = 1;
+    double start, elapsed;
+    int ps = TJ.getPixelSize(pf), tile;
+  
+    FileInputStream fis = new FileInputStream(fileName);
+    int srcSize = (int)fis.getChannel().size();
+    srcBuf = new byte[srcSize];
+    fis.read(srcBuf, 0, srcSize);
+    fis.close();
+
+    int index = fileName.indexOf('.');
+    if (index >= 0)
+      fileName = new String(fileName.substring(0, index));
+
+    tjt = new TJTransformer();
+
+    tjt.setJPEGImage(srcBuf, srcSize);
+    w = tjt.getWidth();
+    h = tjt.getHeight();
+    subsamp = tjt.getSubsamp();
+  
+    if (quiet == 1) {
+      System.out.println("All performance values in Mpixels/sec\n");
+      System.out.format("Bitmap\tBitmap\tJPEG\t%s %s \tXform\tComp\tDecomp\n",
+                        (doTile ? "Tile " : "Image"),
+                        (doTile ? "Tile " : "Image"));
+      System.out.println("Format\tOrder\tSubsamp\tWidth Height\tPerf \tRatio\tPerf\n");
+    } else if (quiet == 0) {
+      System.out.format(">>>>>  JPEG %s --> %s (%s)  <<<<<",
+        subNameLong[subsamp], pixFormatStr[pf],
+        (flags & TJ.FLAG_BOTTOMUP) != 0 ? "Bottom-up" : "Top-down");
+    }
+  
+    for (int tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ;
+         tilew *= 2, tileh *= 2) {
+      if (tilew > w)
+        tilew = w;
+      if (tileh > h)
+        tileh = h;
+      ntilesw = (w + tilew - 1) / tilew;
+      ntilesh = (h + tileh - 1) / tileh;
+  
+      _w = w;  _h = h;  _tilew = tilew;  _tileh = tileh;
+      if (quiet == 0) {
+        System.out.format("\n%s size: %d x %d", (doTile ? "Tile" : "Image"),
+                          _tilew, _tileh);
+        if (sf.getNum() != 1 || sf.getDenom() != 1)
+          System.out.format(" --> %d x %d", sf.getScaled(_w),
+                            sf.getScaled(_h));
+        System.out.println("");
+      } else if (quiet==1) {
+        System.out.format("%s\t%s\t%s\t", pixFormatStr[pf],
+                          (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD",
+                          subNameLong[subsamp]);
+        System.out.format("%-4d  %-4d\t", tilew, tileh);
+      }
+  
+      _subsamp = subsamp;
+      if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0) {
+        if (xformOp == TJTransform.OP_TRANSPOSE ||
+            xformOp == TJTransform.OP_TRANSVERSE ||
+            xformOp == TJTransform.OP_ROT90 ||
+            xformOp == TJTransform.OP_ROT270) {
+          _w = h;  _h = w;  _tilew = tileh;  _tileh = tilew;
+        }
+  
+        if ((xformOpt & TJTransform.OPT_GRAY) != 0)
+          _subsamp = TJ.SAMP_GRAY;
+        if (xformOp == TJTransform.OP_HFLIP ||
+            xformOp == TJTransform.OP_ROT180)
+          _w = _w - (_w % TJ.getMCUWidth(_subsamp));
+        if (xformOp == TJTransform.OP_VFLIP ||
+            xformOp == TJTransform.OP_ROT180)
+          _h = _h - (_h % TJ.getMCUHeight(_subsamp));
+        if (xformOp == TJTransform.OP_TRANSVERSE ||
+            xformOp == TJTransform.OP_ROT90)
+          _w = _w - (_w % TJ.getMCUHeight(_subsamp));
+        if (xformOp == TJTransform.OP_TRANSVERSE ||
+            xformOp == TJTransform.OP_ROT270)
+          _h = _h - (_h % TJ.getMCUWidth(_subsamp));
+        _ntilesw = (_w + _tilew - 1) / _tilew;
+        _ntilesh = (_h + _tileh - 1) / _tileh;
+  
+        TJTransform t[] = new TJTransform[_ntilesw * _ntilesh];
+        jpegBuf = new byte[_ntilesw * _ntilesh][TJ.bufSize(_tilew, _tileh, subsamp)];
+
+        for (y = 0, tile = 0; y < _h; y += _tileh) {
+          for (x = 0; x < _w; x += _tilew, tile++) {
+            t[tile] = new TJTransform();
+            t[tile].width = Math.min(_tilew, _w - x);
+            t[tile].height = Math.min(_tileh, _h - y);
+            t[tile].x = x;
+            t[tile].y = y;
+            t[tile].op = xformOp;
+            t[tile].options = xformOpt | TJTransform.OPT_TRIM;
+            if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 &&
+                jpegBuf[tile] != null)
+              jpegBuf[tile] = null;
+          }
+        }
+  
+        start = getTime();
+        tjt.transform(jpegBuf, t, flags);
+        jpegSize = tjt.getTransformedSizes();
+        elapsed = getTime() - start;
+  
+        t = null;
+  
+        for (tile = 0, totalJpegSize = 0; tile < _ntilesw * _ntilesh; tile++)
+          totalJpegSize += jpegSize[tile];
+  
+        if (quiet != 0) {
+          System.out.format("%s%c%s%c",
+            sigFig((double)(w * h) / 1000000. / elapsed, 4),
+            quiet == 2 ? '\n' : '\t',
+            sigFig((double)(w * h * ps) / (double)totalJpegSize, 4),
+            quiet == 2 ? '\n' : '\t');
+        } else if (quiet == 0) {
+          System.out.format("X--> Frame rate:           %f fps\n",
+                            1.0 / elapsed);
+          System.out.format("     Output image size:    %lu bytes\n",
+                            totalJpegSize);
+          System.out.format("     Compression ratio:    %f:1\n",
+                            (double)(w * h * ps) / (double)totalJpegSize);
+          System.out.format("     Source throughput:    %f Megapixels/sec\n",
+                            (double)(w * h) / 1000000. / elapsed);
+          System.out.format("     Output bit stream:    %f Megabits/sec\n",
+                            (double)totalJpegSize * 8. / 1000000. / elapsed);
+        }
+      } else {
+        if (quiet == 1)
+          System.out.print("N/A\tN/A\t");
+        jpegBuf = new byte[1][TJ.bufSize(_tilew, _tileh, subsamp)];
+        jpegSize = new int[1];
+        jpegSize[0] = srcSize;
+        System.arraycopy(srcBuf, 0, jpegBuf[0], 0, srcSize);
+      }
+  
+      if (w == tilew)
+        _tilew = _w;
+      if (h == tileh)
+        _tileh = _h;
+      if ((xformOpt & TJTransform.OPT_NOOUTPUT) == 0)
+        decompTest(null, jpegBuf, jpegSize, null, _w, _h, _subsamp, 0,
+                   fileName, _tilew, _tileh);
+      else if (quiet == 1)
+        System.out.println("N/A");
+  
+      jpegBuf = null;
+      jpegSize = null;
+  
+      if (tilew == w && tileh == h) break;
+    }
+  }
+  
+  
+  static void usage() throws Exception
+  {
+    int i;
+    TJScalingFactor scalingFactors[] = TJ.getScalingFactors();
+    int nsf = scalingFactors.length;
+    String className = new TJBench().getClass().getName();
+
+    System.out.println("\nUSAGE: java " + className);
+    System.out.println("       <Inputfile (BMP)> <Quality> [options]\n");
+    System.out.println("       java " + className);
+    System.out.println("       <Inputfile (JPG)> [options]\n");
+    System.out.println("Options:\n");
+    System.out.println("-alloc = Dynamically allocate JPEG image buffers");
+    System.out.println("-bottomup = Test bottom-up compression/decompression");
+    System.out.println("-tile = Test performance of the codec when the image is encoded as separate");
+    System.out.println("     tiles of varying sizes.");
+    System.out.println("-forcemmx, -forcesse, -forcesse2, -forcesse3 =");
+    System.out.println("     Force MMX, SSE, SSE2, or SSE3 code paths in the underlying codec");
+    System.out.println("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =");
+    System.out.println("     Test the specified color conversion path in the codec (default: BGR)");
+    System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in");
+    System.out.println("     the underlying codec");
+    System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying");
+    System.out.println("     codec");
+    System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the");
+    System.out.println("     underlying codec");
+    System.out.println("-quiet = Output results in tabular rather than verbose format");
+    System.out.println("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG");
+    System.out.println("-yuvdecode = Decode JPEG image to planar YUV rather than RGB");
+    System.out.println("-scale M/N = scale down the width/height of the decompressed JPEG image by a");
+    System.out.print  ("     factor of M/N (M/N = ");
+    for (i = 0; i < nsf; i++) {
+      System.out.format("%d/%d", scalingFactors[i].getNum(),
+                        scalingFactors[i].getDenom());
+      if (nsf == 2 && i != nsf - 1)
+        System.out.print(" or ");
+      else if (nsf > 2) {
+        if (i != nsf - 1)
+          System.out.print(", ");
+        if (i == nsf - 2)
+          System.out.print("or ");
+      }
+      if (i % 8 == 0 && i != 0)
+        System.out.print("\n     ");
+    }
+    System.out.println(")");
+    System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
+    System.out.println("     Perform the corresponding lossless transform prior to");
+    System.out.println("     decompression (these options are mutually exclusive)");
+    System.out.println("-grayscale = Perform lossless grayscale conversion prior to decompression");
+    System.out.println("     test (can be combined with the other transforms above)");
+    System.out.println("-benchTime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n");
+    System.out.println("NOTE:  If the quality is specified as a range (e.g. 90-100), a separate");
+    System.out.println("test will be performed for all quality values in the range.\n");
+    System.exit(1);
+  }
+  
+  
+  public static void main(String argv[])
+  {
+    byte[] srcBuf = null;  int w = 0, h = 0;
+    int minQual = -1, maxQual = -1;
+    int minArg = 1;  int retval = 0;
+
+    try {
+
+    if (argv.length < minArg)
+      usage();
+  
+    String tempStr = argv[0].toLowerCase();
+    if (tempStr.endsWith(".jpg") || tempStr.endsWith(".jpeg"))
+      decompOnly = true;
+  
+    System.out.println("");
+  
+    if (argv.length > minArg) {
+      for (int i = minArg; i < argv.length; i++) {
+        if (argv[i].equalsIgnoreCase("-yuvencode")) {
+          System.out.println("Testing YUV planar encoding\n");
+          yuv = YUVENCODE;  maxQual = minQual = 100;
+        }
+        if (argv[i].equalsIgnoreCase("-yuvdecode")) {
+          System.out.println("Testing YUV planar decoding\n");
+          yuv = YUVDECODE;
+        }
+      }
+    }
+
+    if (!decompOnly && yuv != YUVENCODE) {
+      minArg = 2;
+      if (argv.length < minArg)
+        usage();
+      try {
+        minQual = Integer.parseInt(argv[1]);
+      } catch (NumberFormatException e) {}
+      if (minQual < 1 || minQual > 100)
+        throw new Exception("Quality must be between 1 and 100.");
+      int dashIndex = argv[1].indexOf('-');
+      if (dashIndex > 0 && argv[1].length() > dashIndex + 1) {
+        try {
+          maxQual = Integer.parseInt(argv[1].substring(dashIndex + 1));
+        } catch (NumberFormatException e) {}
+      }
+      if (maxQual < 1 || maxQual > 100)
+        maxQual = minQual;
+    }
+  
+    if (argv.length > minArg) {
+      for (int i = minArg; i < argv.length; i++) {
+        if (argv[i].equalsIgnoreCase("-tile")) {
+          doTile = true;  xformOpt |= TJTransform.OPT_CROP;
+        }
+        if (argv[i].equalsIgnoreCase("-forcesse3")) {
+          System.out.println("Forcing SSE3 code\n");
+          flags |= TJ.FLAG_FORCESSE3;
+        }
+        if (argv[i].equalsIgnoreCase("-forcesse2")) {
+          System.out.println("Forcing SSE2 code\n");
+          flags |= TJ.FLAG_FORCESSE2;
+        }
+        if (argv[i].equalsIgnoreCase("-forcesse")) {
+          System.out.println("Forcing SSE code\n");
+          flags |= TJ.FLAG_FORCESSE;
+        }
+        if (argv[i].equalsIgnoreCase("-forcemmx")) {
+          System.out.println("Forcing MMX code\n");
+          flags |= TJ.FLAG_FORCEMMX;
+        }
+        if (argv[i].equalsIgnoreCase("-fastupsample")) {
+          System.out.println("Using fast upsampling code\n");
+          flags |= TJ.FLAG_FASTUPSAMPLE;
+        }
+        if (argv[i].equalsIgnoreCase("-fastdct")) {
+          System.out.println("Using fastest DCT/IDCT algorithm\n");
+          flags |= TJ.FLAG_FASTDCT;
+        }
+        if (argv[i].equalsIgnoreCase("-accuratedct")) {
+          System.out.println("Using most accurate DCT/IDCT algorithm\n");
+          flags |= TJ.FLAG_ACCURATEDCT;
+        }
+        if (argv[i].equalsIgnoreCase("-rgb"))
+          pf = TJ.PF_RGB;
+        if (argv[i].equalsIgnoreCase("-rgbx"))
+          pf = TJ.PF_RGBX;
+        if (argv[i].equalsIgnoreCase("-bgr"))
+          pf = TJ.PF_BGR;
+        if (argv[i].equalsIgnoreCase("-bgrx"))
+          pf = TJ.PF_BGRX;
+        if (argv[i].equalsIgnoreCase("-xbgr"))
+          pf = TJ.PF_XBGR;
+        if (argv[i].equalsIgnoreCase("-xrgb"))
+          pf = TJ.PF_XRGB;
+        if (argv[i].equalsIgnoreCase("-bottomup"))
+          flags |= TJ.FLAG_BOTTOMUP;
+        if (argv[i].equalsIgnoreCase("-quiet"))
+          quiet = 1;
+        if (argv[i].equalsIgnoreCase("-qq"))
+          quiet = 2;
+        if (argv[i].equalsIgnoreCase("-scale") && i < argv.length - 1) {
+          int temp1 = 0, temp2 = 0;
+          boolean match = false, scanned = true;
+          Scanner scanner = new Scanner(argv[++i]).useDelimiter("/");
+          try {
+            temp1 = scanner.nextInt();
+            temp2 = scanner.nextInt();
+          } catch(Exception e) {}
+          if (temp2 <= 0) temp2 = 1;
+          if (temp1 > 0) {
+            TJScalingFactor scalingFactors[] = TJ.getScalingFactors();
+            for (int j = 0; j < scalingFactors.length; j++) {
+              if ((double)temp1 / (double)temp2 ==
+                  (double)scalingFactors[j].getNum() /
+                  (double)scalingFactors[j].getDenom()) {
+                sf = scalingFactors[j];
+                match = true;   break;
+              }
+            }
+            if (!match) usage();
+          } else
+            usage();
+        }
+        if (argv[i].equalsIgnoreCase("-hflip"))
+          xformOp = TJTransform.OP_HFLIP;
+        if (argv[i].equalsIgnoreCase("-vflip"))
+          xformOp = TJTransform.OP_VFLIP;
+        if (argv[i].equalsIgnoreCase("-transpose"))
+          xformOp = TJTransform.OP_TRANSPOSE;
+        if (argv[i].equalsIgnoreCase("-transverse"))
+          xformOp = TJTransform.OP_TRANSVERSE;
+        if (argv[i].equalsIgnoreCase("-rot90"))
+          xformOp = TJTransform.OP_ROT90;
+        if (argv[i].equalsIgnoreCase("-rot180"))
+          xformOp = TJTransform.OP_ROT180;
+        if (argv[i].equalsIgnoreCase("-rot270"))
+          xformOp = TJTransform.OP_ROT270;
+        if (argv[i].equalsIgnoreCase("-grayscale"))
+          xformOpt |= TJTransform.OPT_GRAY;
+        if (argv[i].equalsIgnoreCase("-nooutput"))
+          xformOpt |= TJTransform.OPT_NOOUTPUT;
+        if (argv[i].equalsIgnoreCase("-benchtime") && i < argv.length - 1) {
+          double temp = -1;
+          try {
+            temp = Double.parseDouble(argv[++i]);
+          } catch (NumberFormatException e) {}
+          if (temp > 0.0)
+            benchTime = temp;
+          else
+            usage();
+        }
+        if (argv[i].equalsIgnoreCase("-?"))
+          usage();
+      }
+    }
+
+    if (sf == null)
+      sf = new TJScalingFactor(1, 1);
+  
+    if ((sf.getNum() != 1 || sf.getDenom() != 1) && doTile) {
+      System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
+      System.out.println("work when scaled decompression is enabled.");
+      doTile = false;
+    }
+  
+    if (yuv != 0 && doTile) {
+      System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
+      System.out.println("work when YUV encoding or decoding is enabled.\n");
+      doTile = false;
+    }
+  
+    if (!decompOnly) {
+      int[] width = new int[1], height = new int[1];
+      srcBuf = loadImage(argv[0], width, height, pf);
+      w = width[0];  h = height[0];
+      int index = -1;
+      if ((index = argv[0].indexOf('.')) >= 0)
+        argv[0] = argv[0].substring(0, index);
+    }
+  
+    if (quiet == 1 && !decompOnly) {
+      System.out.println("All performance values in Mpixels/sec\n");
+      System.out.format("Bitmap\tBitmap\tJPEG\tJPEG\t%s %s \tComp\tComp\tDecomp\n",
+        (doTile ? "Tile " : "Image"), (doTile ? "Tile " : "Image"));
+      System.out.println("Format\tOrder\tSubsamp\tQual\tWidth Height\tPerf \tRatio\tPerf\n");
+    }
+  
+    if (decompOnly) {
+      doDecompTest(argv[0]);
+      System.out.println("");
+      System.exit(retval);
+    }
+
+    System.gc();
+    for (int i = maxQual; i >= minQual; i--)
+      doTest(srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]);
+    System.out.println("");
+    System.gc();
+    for (int i = maxQual; i >= minQual; i--)
+      doTest(srcBuf, w, h, TJ.SAMP_420, i, argv[0]);
+    System.out.println("");
+    System.gc();
+    for (int i = maxQual; i >= minQual; i--)
+      doTest(srcBuf, w, h, TJ.SAMP_422, i, argv[0]);
+    System.out.println("");
+    System.gc();
+    for (int i = maxQual; i >= minQual; i--)
+      doTest(srcBuf, w, h, TJ.SAMP_444, i, argv[0]);
+    System.out.println("");
+
+    } catch (Exception e) {
+      System.out.println("ERROR: " + e.getMessage());
+      e.printStackTrace();
+      retval = -1;
+    }
+  
+    System.exit(retval);
+  }
+
+}
diff --git a/java/doc/allclasses-frame.html b/java/doc/allclasses-frame.html
index 336473c..7c849be 100644
--- a/java/doc/allclasses-frame.html
+++ b/java/doc/allclasses-frame.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 All Classes
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/allclasses-noframe.html b/java/doc/allclasses-noframe.html
index ad7cd9e..543efe1 100644
--- a/java/doc/allclasses-noframe.html
+++ b/java/doc/allclasses-noframe.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 All Classes
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/constant-values.html b/java/doc/constant-values.html
index 8cf0ae7..0f788af 100644
--- a/java/doc/constant-values.html
+++ b/java/doc/constant-values.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 Constant Field Values
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/deprecated-list.html b/java/doc/deprecated-list.html
index b7d3689..8ba7084 100644
--- a/java/doc/deprecated-list.html
+++ b/java/doc/deprecated-list.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 Deprecated List
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/help-doc.html b/java/doc/help-doc.html
index fc2ff59..2382c7b 100644
--- a/java/doc/help-doc.html
+++ b/java/doc/help-doc.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 API Help
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/index-all.html b/java/doc/index-all.html
index 69d4104..690cc07 100644
--- a/java/doc/index-all.html
+++ b/java/doc/index-all.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 Index
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="./stylesheet.css" TITLE="Style">
 
@@ -479,6 +479,9 @@
 <DT><A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html#setJPEGQuality(int)"><B>setJPEGQuality(int)</B></A> - 
 Method in class org.libjpegturbo.turbojpeg.<A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</A>
 <DD>Set the JPEG image quality level for subsequent compress operations.
+<DT><A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><B>setSourceImage(byte[], int, int, int, int, int, int)</B></A> - 
+Method in class org.libjpegturbo.turbojpeg.<A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</A>
+<DD>Associate an uncompressed source image with this compressor instance.
 <DT><A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><B>setSourceImage(byte[], int, int, int, int)</B></A> - 
 Method in class org.libjpegturbo.turbojpeg.<A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</A>
 <DD>Associate an uncompressed source image with this compressor instance.
@@ -502,6 +505,11 @@
 <DD>Create a TurboJPEG compressor instance and associate the uncompressed
  source image stored in <code>srcImage</code> with the newly-created
  instance.
+<DT><A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[], int, int, int, int, int, int)"><B>TJCompressor(byte[], int, int, int, int, int, int)</B></A> - 
+Constructor for class org.libjpegturbo.turbojpeg.<A HREF="./org/libjpegturbo/turbojpeg/TJCompressor.html" title="class in org.libjpegturbo.turbojpeg">TJCompressor</A>
+<DD>Create a TurboJPEG compressor instance and associate the uncompressed
+ source image stored in <code>srcImage</code> with the newly-created
+ instance.
 <DT><A HREF="./org/libjpegturbo/turbojpeg/TJCustomFilter.html" title="interface in org.libjpegturbo.turbojpeg"><B>TJCustomFilter</B></A> - Interface in <A HREF="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</A><DD>Custom filter callback interface<DT><A HREF="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg"><B>TJDecompressor</B></A> - Class in <A HREF="./org/libjpegturbo/turbojpeg/package-summary.html">org.libjpegturbo.turbojpeg</A><DD>TurboJPEG decompressor<DT><A HREF="./org/libjpegturbo/turbojpeg/TJDecompressor.html#TJDecompressor()"><B>TJDecompressor()</B></A> - 
 Constructor for class org.libjpegturbo.turbojpeg.<A HREF="./org/libjpegturbo/turbojpeg/TJDecompressor.html" title="class in org.libjpegturbo.turbojpeg">TJDecompressor</A>
 <DD>Create a TurboJPEG decompresssor instance.
diff --git a/java/doc/index.html b/java/doc/index.html
index f958145..09806e6 100644
--- a/java/doc/index.html
+++ b/java/doc/index.html
@@ -2,7 +2,7 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc on Fri Jun 29 18:36:27 CDT 2012-->
+<!-- Generated by javadoc on Sun Sep 23 19:56:07 CDT 2012-->
 <TITLE>
 Generated Documentation (Untitled)
 </TITLE>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJ.html b/java/doc/org/libjpegturbo/turbojpeg/TJ.html
index c031b1a..30b8265 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJ.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJ.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJ
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
index d7b6c22..d5d08ed 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJCompressor
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
@@ -133,6 +133,20 @@
  source image stored in <code>srcImage</code> with the newly-created
  instance.</TD>
 </TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD><CODE><B><A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#TJCompressor(byte[], int, int, int, int, int, int)">TJCompressor</A></B>(byte[]&nbsp;srcImage,
+             int&nbsp;x,
+             int&nbsp;y,
+             int&nbsp;width,
+             int&nbsp;pitch,
+             int&nbsp;height,
+             int&nbsp;pixelFormat)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create a TurboJPEG compressor instance and associate the uncompressed
+ source image stored in <code>srcImage</code> with the newly-created
+ instance.</TD>
+</TR>
 </TABLE>
 &nbsp;
 <!-- ========== METHOD SUMMARY =========== -->
@@ -271,6 +285,20 @@
 <TR BGCOLOR="white" CLASS="TableRowColor">
 <TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
 <CODE>&nbsp;void</CODE></FONT></TD>
+<TD><CODE><B><A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)">setSourceImage</A></B>(byte[]&nbsp;srcImage,
+               int&nbsp;x,
+               int&nbsp;y,
+               int&nbsp;width,
+               int&nbsp;pitch,
+               int&nbsp;height,
+               int&nbsp;pixelFormat)</CODE>
+
+<BR>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Associate an uncompressed source image with this compressor instance.</TD>
+</TR>
+<TR BGCOLOR="white" CLASS="TableRowColor">
+<TD ALIGN="right" VALIGN="top" WIDTH="1%"><FONT SIZE="-1">
+<CODE>&nbsp;void</CODE></FONT></TD>
 <TD><CODE><B><A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSubsamp(int)">setSubsamp</A></B>(int&nbsp;newSubsamp)</CODE>
 
 <BR>
@@ -330,7 +358,30 @@
  instance.
 <P>
 <DL>
-<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int)</CODE></A> for description<DD><CODE>width</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int)</CODE></A> for description<DD><CODE>pitch</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int)</CODE></A> for description<DD><CODE>height</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int)</CODE></A> for description<DD><CODE>pixelFormat</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int)</CODE></A> for description
+<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>width</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>pitch</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>height</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>pixelFormat</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DL>
+<HR>
+
+<A NAME="TJCompressor(byte[], int, int, int, int, int, int)"><!-- --></A><H3>
+TJCompressor</H3>
+<PRE>
+public <B>TJCompressor</B>(byte[]&nbsp;srcImage,
+                    int&nbsp;x,
+                    int&nbsp;y,
+                    int&nbsp;width,
+                    int&nbsp;pitch,
+                    int&nbsp;height,
+                    int&nbsp;pixelFormat)
+             throws java.lang.Exception</PRE>
+<DL>
+<DD>Create a TurboJPEG compressor instance and associate the uncompressed
+ source image stored in <code>srcImage</code> with the newly-created
+ instance.
+<P>
+<DL>
+<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>x</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>y</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>width</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>pitch</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>height</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description<DD><CODE>pixelFormat</CODE> - see <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for description
 <DT><B>Throws:</B>
 <DD><CODE>java.lang.Exception</CODE></DL>
 </DL>
@@ -345,6 +396,41 @@
 </TR>
 </TABLE>
 
+<A NAME="setSourceImage(byte[], int, int, int, int, int, int)"><!-- --></A><H3>
+setSourceImage</H3>
+<PRE>
+public void <B>setSourceImage</B>(byte[]&nbsp;srcImage,
+                           int&nbsp;x,
+                           int&nbsp;y,
+                           int&nbsp;width,
+                           int&nbsp;pitch,
+                           int&nbsp;height,
+                           int&nbsp;pixelFormat)
+                    throws java.lang.Exception</PRE>
+<DL>
+<DD>Associate an uncompressed source image with this compressor instance.
+<P>
+<DD><DL>
+<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - image buffer containing RGB or grayscale pixels to be
+ compressed<DD><CODE>x</CODE> - x offset (in pixels) of the region from which the JPEG image
+ should be compressed, relative to the start of <code>srcImage</code>.<DD><CODE>y</CODE> - y offset (in pixels) of the region from which the JPEG image
+ should be compressed, relative to the start of <code>srcImage</code>.<DD><CODE>width</CODE> - width (in pixels) of the region in the source image from
+ which the JPEG image should be compressed.<DD><CODE>pitch</CODE> - bytes per line of the source image.  Normally, this should be
+ <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
+ unpadded, but you can use this parameter to, for instance, specify that
+ the scanlines in the source image are padded to a 4-byte boundary or to
+ compress a JPEG image from a region of a larger source image.  You can
+ also be clever and use this parameter to skip lines, etc.  Setting this
+ parameter to 0 is the equivalent of setting it to <code>width *
+ TJ.pixelSize(pixelFormat)</code>.<DD><CODE>height</CODE> - height (in pixels) of the region in the source image from
+ which the JPEG image should be compressed.<DD><CODE>pixelFormat</CODE> - pixel format of the source image (one of
+ <A HREF="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><CODE>TJ.PF_*</CODE></A>)
+<DT><B>Throws:</B>
+<DD><CODE>java.lang.Exception</CODE></DL>
+</DD>
+</DL>
+<HR>
+
 <A NAME="setSourceImage(byte[], int, int, int, int)"><!-- --></A><H3>
 setSourceImage</H3>
 <PRE>
@@ -358,15 +444,15 @@
 <DD>Associate an uncompressed source image with this compressor instance.
 <P>
 <DD><DL>
-<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - image buffer containing RGB or grayscale pixels to be
- compressed<DD><CODE>width</CODE> - width (in pixels) of the source image<DD><CODE>pitch</CODE> - bytes per line of the source image.  Normally, this should be
- <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
- unpadded, but you can use this parameter to, for instance, specify that
- the scanlines in the source image are padded to 4-byte boundaries, as is
- the case for Windows bitmaps.  You can also be clever and use this
- parameter to skip lines, etc.  Setting this parameter to 0 is the
- equivalent of setting it to <code>width *
- TJ.pixelSize(pixelFormat)</code>.<DD><CODE>height</CODE> - height (in pixels) of the source image<DD><CODE>pixelFormat</CODE> - pixel format of the source image (one of
+<DT><B>Parameters:</B><DD><CODE>srcImage</CODE> - see
+ <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for
+ description<DD><CODE>width</CODE> - see
+ <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for
+ description<DD><CODE>pitch</CODE> - see
+ <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for
+ description<DD><CODE>height</CODE> - see
+ <A HREF="../../../org/libjpegturbo/turbojpeg/TJCompressor.html#setSourceImage(byte[], int, int, int, int, int, int)"><CODE>setSourceImage(byte[], int, int, int, int, int, int)</CODE></A> for
+ description<DD><CODE>pixelFormat</CODE> - pixel format of the source image (one of
  <A HREF="../../../org/libjpegturbo/turbojpeg/TJ.html" title="class in org.libjpegturbo.turbojpeg"><CODE>TJ.PF_*</CODE></A>)
 <DT><B>Throws:</B>
 <DD><CODE>java.lang.Exception</CODE></DL>
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
index 7ae4767..09b8b22 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJCustomFilter
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
index cd5b9eb..0e2fef5 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJDecompressor
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
index 38e4c78..418da03 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJScalingFactor
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
index c521d53..820c515 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJTransform
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
index 11f1d4e..154e8d1 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 TJTransformer
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
index b340c9d..83c3c7e 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 org.libjpegturbo.turbojpeg
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
index 89d2e04..1cd4b40 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 org.libjpegturbo.turbojpeg
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
index da7e743..fcdb173 100644
--- a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
+++ b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 org.libjpegturbo.turbojpeg Class Hierarchy
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="../../../stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/overview-tree.html b/java/doc/overview-tree.html
index b161e73..19c4fce 100644
--- a/java/doc/overview-tree.html
+++ b/java/doc/overview-tree.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 Class Hierarchy
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/doc/serialized-form.html b/java/doc/serialized-form.html
index b626f00..bed4b1b 100644
--- a/java/doc/serialized-form.html
+++ b/java/doc/serialized-form.html
@@ -2,12 +2,12 @@
 <!--NewPage-->
 <HTML>
 <HEAD>
-<!-- Generated by javadoc (build 1.6.0_33) on Fri Jun 29 18:36:27 CDT 2012 -->
+<!-- Generated by javadoc (build 1.6.0_35) on Sun Sep 23 19:56:07 CDT 2012 -->
 <TITLE>
 Serialized Form
 </TITLE>
 
-<META NAME="date" CONTENT="2012-06-29">
+<META NAME="date" CONTENT="2012-09-23">
 
 <LINK REL ="stylesheet" TYPE="text/css" HREF="stylesheet.css" TITLE="Style">
 
diff --git a/java/org/libjpegturbo/turbojpeg/TJCompressor.java b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
index b3c9b95..9f76b42 100644
--- a/java/org/libjpegturbo/turbojpeg/TJCompressor.java
+++ b/java/org/libjpegturbo/turbojpeg/TJCompressor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C)2011 D. R. Commander.  All Rights Reserved.
+ * Copyright (C)2011-2012 D. R. Commander.  All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -67,32 +67,64 @@
   }
 
   /**
+   * Create a TurboJPEG compressor instance and associate the uncompressed
+   * source image stored in <code>srcImage</code> with the newly-created
+   * instance.
+   *
+   * @param srcImage see {@link #setSourceImage} for description
+   *
+   * @param x see {@link #setSourceImage} for description
+   *
+   * @param y see {@link #setSourceImage} for description
+   *
+   * @param width see {@link #setSourceImage} for description
+   *
+   * @param pitch see {@link #setSourceImage} for description
+   *
+   * @param height see {@link #setSourceImage} for description
+   *
+   * @param pixelFormat see {@link #setSourceImage} for description
+   */
+  public TJCompressor(byte[] srcImage, int x, int y, int width, int pitch,
+    int height, int pixelFormat) throws Exception {
+    setSourceImage(srcImage, x, y, width, pitch, height, pixelFormat);
+  }
+
+  /**
    * Associate an uncompressed source image with this compressor instance.
    *
    * @param srcImage image buffer containing RGB or grayscale pixels to be
    * compressed
    *
-   * @param width width (in pixels) of the source image
+   * @param x x offset (in pixels) of the region from which the JPEG image
+   * should be compressed, relative to the start of <code>srcImage</code>.
+   *
+   * @param y y offset (in pixels) of the region from which the JPEG image
+   * should be compressed, relative to the start of <code>srcImage</code>.
+   *
+   * @param width width (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed.
    *
    * @param pitch bytes per line of the source image.  Normally, this should be
    * <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is
    * unpadded, but you can use this parameter to, for instance, specify that
-   * the scanlines in the source image are padded to 4-byte boundaries, as is
-   * the case for Windows bitmaps.  You can also be clever and use this
-   * parameter to skip lines, etc.  Setting this parameter to 0 is the
-   * equivalent of setting it to <code>width *
+   * the scanlines in the source image are padded to a 4-byte boundary or to
+   * compress a JPEG image from a region of a larger source image.  You can
+   * also be clever and use this parameter to skip lines, etc.  Setting this
+   * parameter to 0 is the equivalent of setting it to <code>width *
    * TJ.pixelSize(pixelFormat)</code>.
    *
-   * @param height height (in pixels) of the source image
+   * @param height height (in pixels) of the region in the source image from
+   * which the JPEG image should be compressed.
    *
    * @param pixelFormat pixel format of the source image (one of
    * {@link TJ TJ.PF_*})
    */
-  public void setSourceImage(byte[] srcImage, int width, int pitch,
-    int height, int pixelFormat) throws Exception {
+  public void setSourceImage(byte[] srcImage, int x, int y, int width,
+    int pitch, int height, int pixelFormat) throws Exception {
     if(handle == 0) init();
-    if(srcImage == null || width < 1 || height < 1 || pitch < 0
-      || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
+    if(srcImage == null || x < 0 || y < 0 || width < 1 || height < 1
+      || pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF)
       throw new Exception("Invalid argument in setSourceImage()");
     srcBuf = srcImage;
     srcWidth = width;
@@ -100,9 +132,41 @@
     else srcPitch = pitch;
     srcHeight = height;
     srcPixelFormat = pixelFormat;
+    srcX = x;
+    srcY = y;
   }
 
   /**
+   * Associate an uncompressed source image with this compressor instance.
+   *
+   * @param srcImage see
+   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
+   * description
+   *
+   * @param width see
+   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
+   * description
+   *
+   * @param pitch see
+   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
+   * description
+   *
+   * @param height see
+   * {@link #setSourceImage(byte[], int, int, int, int, int, int)} for
+   * description
+   *
+   * @param pixelFormat pixel format of the source image (one of
+   * {@link TJ TJ.PF_*})
+   */
+
+  public void setSourceImage(byte[] srcImage, int width, int pitch,
+    int height, int pixelFormat) throws Exception {
+    setSourceImage(srcImage, 0, 0, width, pitch, height, pixelFormat);
+    srcX = srcY = -1;
+  }
+
+
+  /**
    * Set the level of chrominance subsampling for subsequent compress/encode
    * operations.
    *
@@ -143,8 +207,12 @@
     if(srcBuf == null) throw new Exception(NO_ASSOC_ERROR);
     if(jpegQuality < 0) throw new Exception("JPEG Quality not set");
     if(subsamp < 0) throw new Exception("Subsampling level not set");
-    compressedSize = compress(srcBuf, srcWidth, srcPitch,
-      srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
+    if (srcX >= 0 && srcY >= 0)
+      compressedSize = compress(srcBuf, srcX, srcY, srcWidth, srcPitch,
+        srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
+    else
+      compressedSize = compress(srcBuf, srcWidth, srcPitch,
+        srcHeight, srcPixelFormat, dstBuf, subsamp, jpegQuality, flags);
   }
 
   /**
@@ -221,8 +289,12 @@
       int pitch = sm.getScanlineStride();
       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
       int[] buf = db.getData();
-      compressedSize = compress(buf, width, pitch, height, pixelFormat, dstBuf,
-        subsamp, jpegQuality, flags);
+      if (srcX >= 0 && srcY >= 0)
+        compressedSize = compress(buf, srcX, srcY, width, pitch, height,
+          pixelFormat, dstBuf, subsamp, jpegQuality, flags);
+      else
+        compressedSize = compress(buf, width, pitch, height, pixelFormat,
+          dstBuf, subsamp, jpegQuality, flags);
     }
     else {
       ComponentSampleModel sm =
@@ -233,8 +305,12 @@
       int pitch = sm.getScanlineStride();
       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
       byte[] buf = db.getData();
-      compressedSize = compress(buf, width, pitch, height, pixelFormat, dstBuf,
-        subsamp, jpegQuality, flags);
+      if (srcX >= 0 && srcY >= 0)
+        compressedSize = compress(buf, srcX, srcY, width, pitch, height,
+          pixelFormat, dstBuf, subsamp, jpegQuality, flags);
+      else
+        compressedSize = compress(buf, width, pitch, height, pixelFormat,
+          dstBuf, subsamp, jpegQuality, flags);
     }
   }
 
@@ -438,19 +514,27 @@
 
   // JPEG size in bytes is returned
   private native int compress(byte[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] dstbuf, int jpegSubsamp, int jpegQual,
+    int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
     int flags) throws Exception;
 
-  private native int compress(int[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] dstbuf, int jpegSubsamp, int jpegQual,
+  private native int compress(byte[] srcBuf, int x, int y, int width,
+    int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
+    int jpegQual, int flags) throws Exception;
+
+  private native int compress(int[] srcBuf, int width, int stride,
+    int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual,
     int flags) throws Exception;
 
+  private native int compress(int[] srcBuf, int x, int y, int width,
+    int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp,
+    int jpegQual, int flags) throws Exception;
+
   private native void encodeYUV(byte[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] dstbuf, int subsamp, int flags)
+    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
     throws Exception;
 
   private native void encodeYUV(int[] srcBuf, int width, int pitch,
-    int height, int pixelFormat, byte[] dstbuf, int subsamp, int flags)
+    int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)
     throws Exception;
 
   static {
@@ -461,6 +545,8 @@
   private byte[] srcBuf = null;
   private int srcWidth = 0;
   private int srcHeight = 0;
+  private int srcX = -1;
+  private int srcY = -1;
   private int srcPitch = 0;
   private int srcPixelFormat = -1;
   private int subsamp = -1;
diff --git a/java/org_libjpegturbo_turbojpeg_TJ.h b/java/org_libjpegturbo_turbojpeg_TJ.h
index c892086..d7b032a 100644
--- a/java/org_libjpegturbo_turbojpeg_TJ.h
+++ b/java/org_libjpegturbo_turbojpeg_TJ.h
@@ -55,6 +55,10 @@
 #define org_libjpegturbo_turbojpeg_TJ_FLAG_FORCESSE3 128L
 #undef org_libjpegturbo_turbojpeg_TJ_FLAG_FASTUPSAMPLE
 #define org_libjpegturbo_turbojpeg_TJ_FLAG_FASTUPSAMPLE 256L
+#undef org_libjpegturbo_turbojpeg_TJ_FLAG_FASTDCT
+#define org_libjpegturbo_turbojpeg_TJ_FLAG_FASTDCT 2048L
+#undef org_libjpegturbo_turbojpeg_TJ_FLAG_ACCURATEDCT
+#define org_libjpegturbo_turbojpeg_TJ_FLAG_ACCURATEDCT 4096L
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJ
  * Method:    bufSize
diff --git a/java/org_libjpegturbo_turbojpeg_TJCompressor.h b/java/org_libjpegturbo_turbojpeg_TJCompressor.h
index 59f81e3..2fc9136 100644
--- a/java/org_libjpegturbo_turbojpeg_TJCompressor.h
+++ b/java/org_libjpegturbo_turbojpeg_TJCompressor.h
@@ -34,6 +34,14 @@
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
  * Method:    compress
+ * Signature: ([BIIIIII[BIII)I
+ */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
+  (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJCompressor
+ * Method:    compress
  * Signature: ([IIIII[BIII)I
  */
 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
@@ -41,6 +49,14 @@
 
 /*
  * Class:     org_libjpegturbo_turbojpeg_TJCompressor
+ * Method:    compress
+ * Signature: ([IIIIIII[BIII)I
+ */
+JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
+  (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jint, jint, jbyteArray, jint, jint, jint);
+
+/*
+ * Class:     org_libjpegturbo_turbojpeg_TJCompressor
  * Method:    encodeYUV
  * Signature: ([BIIII[BII)V
  */