diff --git a/ChangeLog.txt b/ChangeLog.txt index c4c5ddc9..a060d94d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -12,8 +12,9 @@ function is provided to maintain backward compatibility. However, certain Linux distro maintainers will blindly reject any library that is not versioned, so this was an attempt to make them happy. -[3] Extended the TurboJPEG Java API so that it can be used to decompress a -JPEG image into an arbitrary position in a large output buffer. +[3] Extended the TurboJPEG Java API so that it can be used to compress a JPEG +image from and decompress a JPEG image to an arbitrary position in a large +image buffer. [4] The tjDecompressToYUV() function now supports the TJFLAG_FASTDCT flag. diff --git a/Makefile.am b/Makefile.am index 942892d7..838c6262 100644 --- a/Makefile.am +++ b/Makefile.am @@ -234,7 +234,7 @@ testclean: tjtest: sh ./tjbenchtest if WITH_JAVA - sh ./tjexampletest + sh ./tjbenchtest.java endif diff --git a/configure.ac b/configure.ac index 0edc4021..31a5ee56 100644 --- a/configure.ac +++ b/configure.ac @@ -367,6 +367,7 @@ 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([tjbenchtest]) +AC_CONFIG_FILES([tjbenchtest.java]) AC_CONFIG_FILES([tjexampletest]) AC_CONFIG_FILES([libjpeg.map]) AC_CONFIG_FILES([Makefile simd/Makefile]) diff --git a/java/CMakeLists.txt b/java/CMakeLists.txt index 87f8ec6c..87db412e 100644 --- a/java/CMakeLists.txt +++ b/java/CMakeLists.txt @@ -9,7 +9,8 @@ set(JAVA_CLASSNAMES org/libjpegturbo/turbojpeg/TJ 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 4a1b34ef..6896fa2f 100644 --- a/java/Makefile.am +++ b/java/Makefile.am @@ -9,7 +9,8 @@ JAVASOURCES = org/libjpegturbo/turbojpeg/TJ.java \ 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 @@ JAVA_CLASSES = org/libjpegturbo/turbojpeg/TJ.class \ 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 00000000..2f27b8e1 --- /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(" [options]\n"); + System.out.println(" java " + className); + System.out.println(" [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 = Run each benchmark for at least 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 336473c8..7c849bed 100644 --- a/java/doc/allclasses-frame.html +++ b/java/doc/allclasses-frame.html @@ -2,12 +2,12 @@ - + All Classes - + diff --git a/java/doc/allclasses-noframe.html b/java/doc/allclasses-noframe.html index ad7cd9e8..543efe16 100644 --- a/java/doc/allclasses-noframe.html +++ b/java/doc/allclasses-noframe.html @@ -2,12 +2,12 @@ - + All Classes - + diff --git a/java/doc/constant-values.html b/java/doc/constant-values.html index 8cf0ae7b..0f788af5 100644 --- a/java/doc/constant-values.html +++ b/java/doc/constant-values.html @@ -2,12 +2,12 @@ - + Constant Field Values - + diff --git a/java/doc/deprecated-list.html b/java/doc/deprecated-list.html index b7d3689e..8ba70846 100644 --- a/java/doc/deprecated-list.html +++ b/java/doc/deprecated-list.html @@ -2,12 +2,12 @@ - + Deprecated List - + diff --git a/java/doc/help-doc.html b/java/doc/help-doc.html index fc2ff59b..2382c7b6 100644 --- a/java/doc/help-doc.html +++ b/java/doc/help-doc.html @@ -2,12 +2,12 @@ - + API Help - + diff --git a/java/doc/index-all.html b/java/doc/index-all.html index 69d41044..690cc071 100644 --- a/java/doc/index-all.html +++ b/java/doc/index-all.html @@ -2,12 +2,12 @@ - + Index - + @@ -479,6 +479,9 @@ Method in class org.libjpegturbo.turbojpeg.setJPEGQuality(int) - Method in class org.libjpegturbo.turbojpeg.TJCompressor
Set the JPEG image quality level for subsequent compress operations. +
setSourceImage(byte[], int, int, int, int, int, int) - +Method in class org.libjpegturbo.turbojpeg.TJCompressor +
Associate an uncompressed source image with this compressor instance.
setSourceImage(byte[], int, int, int, int) - Method in class org.libjpegturbo.turbojpeg.TJCompressor
Associate an uncompressed source image with this compressor instance. @@ -499,6 +502,11 @@ Constructor for class org.libjpegturbo.turbojpeg.TJCompressor(byte[], int, int, int, int) - Constructor for class org.libjpegturbo.turbojpeg.TJCompressor +
Create a TurboJPEG compressor instance and associate the uncompressed + source image stored in srcImage with the newly-created + instance. +
TJCompressor(byte[], int, int, int, int, int, int) - +Constructor for class org.libjpegturbo.turbojpeg.TJCompressor
Create a TurboJPEG compressor instance and associate the uncompressed source image stored in srcImage with the newly-created instance. diff --git a/java/doc/index.html b/java/doc/index.html index f9581452..09806e68 100644 --- a/java/doc/index.html +++ b/java/doc/index.html @@ -2,7 +2,7 @@ - + Generated Documentation (Untitled) diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJ.html b/java/doc/org/libjpegturbo/turbojpeg/TJ.html index c031b1ab..30b82651 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJ.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJ.html @@ -2,12 +2,12 @@ - + TJ - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html index d7b6c22c..d5d08ed8 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJCompressor.html @@ -2,12 +2,12 @@ - + TJCompressor - + @@ -128,6 +128,20 @@ TurboJPEG compressor int height, int pixelFormat) +
+          Create a TurboJPEG compressor instance and associate the uncompressed + source image stored in srcImage with the newly-created + instance. + + +TJCompressor(byte[] srcImage, + int x, + int y, + int width, + int pitch, + int height, + int pixelFormat) +
          Create a TurboJPEG compressor instance and associate the uncompressed source image stored in srcImage with the newly-created @@ -265,6 +279,20 @@ TurboJPEG compressor int height, int pixelFormat) +
+          Associate an uncompressed source image with this compressor instance. + + + + void +setSourceImage(byte[] srcImage, + int x, + int y, + int width, + int pitch, + int height, + int pixelFormat) +
          Associate an uncompressed source image with this compressor instance. @@ -330,7 +358,30 @@ public TJCompressor(byte[] srcImage, instance.

-
Parameters:
srcImage - see setSourceImage(byte[], int, int, int, int) for description
width - see setSourceImage(byte[], int, int, int, int) for description
pitch - see setSourceImage(byte[], int, int, int, int) for description
height - see setSourceImage(byte[], int, int, int, int) for description
pixelFormat - see setSourceImage(byte[], int, int, int, int) for description +
Parameters:
srcImage - see setSourceImage(byte[], int, int, int, int, int, int) for description
width - see setSourceImage(byte[], int, int, int, int, int, int) for description
pitch - see setSourceImage(byte[], int, int, int, int, int, int) for description
height - see setSourceImage(byte[], int, int, int, int, int, int) for description
pixelFormat - see setSourceImage(byte[], int, int, int, int, int, int) for description +
Throws: +
java.lang.Exception
+ +
+ +

+TJCompressor

+
+public TJCompressor(byte[] srcImage,
+                    int x,
+                    int y,
+                    int width,
+                    int pitch,
+                    int height,
+                    int pixelFormat)
+             throws java.lang.Exception
+
+
Create a TurboJPEG compressor instance and associate the uncompressed + source image stored in srcImage with the newly-created + instance. +

+

+
Parameters:
srcImage - see setSourceImage(byte[], int, int, int, int, int, int) for description
x - see setSourceImage(byte[], int, int, int, int, int, int) for description
y - see setSourceImage(byte[], int, int, int, int, int, int) for description
width - see setSourceImage(byte[], int, int, int, int, int, int) for description
pitch - see setSourceImage(byte[], int, int, int, int, int, int) for description
height - see setSourceImage(byte[], int, int, int, int, int, int) for description
pixelFormat - see setSourceImage(byte[], int, int, int, int, int, int) for description
Throws:
java.lang.Exception
@@ -345,6 +396,41 @@ public TJCompressor(byte[] srcImage, +

+setSourceImage

+
+public void setSourceImage(byte[] srcImage,
+                           int x,
+                           int y,
+                           int width,
+                           int pitch,
+                           int height,
+                           int pixelFormat)
+                    throws java.lang.Exception
+
+
Associate an uncompressed source image with this compressor instance. +

+

+
Parameters:
srcImage - image buffer containing RGB or grayscale pixels to be + compressed
x - x offset (in pixels) of the region from which the JPEG image + should be compressed, relative to the start of srcImage.
y - y offset (in pixels) of the region from which the JPEG image + should be compressed, relative to the start of srcImage.
width - width (in pixels) of the region in the source image from + which the JPEG image should be compressed.
pitch - bytes per line of the source image. Normally, this should be + width * TJ.pixelSize(pixelFormat) 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 width * + TJ.pixelSize(pixelFormat).
height - height (in pixels) of the region in the source image from + which the JPEG image should be compressed.
pixelFormat - pixel format of the source image (one of + TJ.PF_*) +
Throws: +
java.lang.Exception
+
+
+
+

setSourceImage

@@ -358,15 +444,15 @@ public void setSourceImage(byte[] srcImage,
 
Associate an uncompressed source image with this compressor instance.

-
Parameters:
srcImage - image buffer containing RGB or grayscale pixels to be - compressed
width - width (in pixels) of the source image
pitch - bytes per line of the source image. Normally, this should be - width * TJ.pixelSize(pixelFormat) 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 width * - TJ.pixelSize(pixelFormat).
height - height (in pixels) of the source image
pixelFormat - pixel format of the source image (one of +
Parameters:
srcImage - see + setSourceImage(byte[], int, int, int, int, int, int) for + description
width - see + setSourceImage(byte[], int, int, int, int, int, int) for + description
pitch - see + setSourceImage(byte[], int, int, int, int, int, int) for + description
height - see + setSourceImage(byte[], int, int, int, int, int, int) for + description
pixelFormat - pixel format of the source image (one of TJ.PF_*)
Throws:
java.lang.Exception
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html index 7ae47673..09b8b227 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJCustomFilter.html @@ -2,12 +2,12 @@ - + TJCustomFilter - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html index cd5b9eb8..0e2fef53 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html @@ -2,12 +2,12 @@ - + TJDecompressor - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html index 38e4c78d..418da03d 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJScalingFactor.html @@ -2,12 +2,12 @@ - + TJScalingFactor - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html index c521d532..820c515d 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html @@ -2,12 +2,12 @@ - + TJTransform - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html index 11f1d4e7..154e8d19 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransformer.html @@ -2,12 +2,12 @@ - + TJTransformer - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html index b340c9d4..83c3c7ec 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/package-frame.html +++ b/java/doc/org/libjpegturbo/turbojpeg/package-frame.html @@ -2,12 +2,12 @@ - + org.libjpegturbo.turbojpeg - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html index 89d2e04f..1cd4b405 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/package-summary.html +++ b/java/doc/org/libjpegturbo/turbojpeg/package-summary.html @@ -2,12 +2,12 @@ - + org.libjpegturbo.turbojpeg - + diff --git a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html index da7e7437..fcdb1731 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/package-tree.html +++ b/java/doc/org/libjpegturbo/turbojpeg/package-tree.html @@ -2,12 +2,12 @@ - + org.libjpegturbo.turbojpeg Class Hierarchy - + diff --git a/java/doc/overview-tree.html b/java/doc/overview-tree.html index b161e739..19c4fcef 100644 --- a/java/doc/overview-tree.html +++ b/java/doc/overview-tree.html @@ -2,12 +2,12 @@ - + Class Hierarchy - + diff --git a/java/doc/serialized-form.html b/java/doc/serialized-form.html index b626f001..bed4b1bc 100644 --- a/java/doc/serialized-form.html +++ b/java/doc/serialized-form.html @@ -2,12 +2,12 @@ - + Serialized Form - + diff --git a/java/org/libjpegturbo/turbojpeg/TJCompressor.java b/java/org/libjpegturbo/turbojpeg/TJCompressor.java index b3c9b956..9f76b42a 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: @@ -66,33 +66,65 @@ public class TJCompressor { setSourceImage(srcImage, width, pitch, height, pixelFormat); } + /** + * Create a TurboJPEG compressor instance and associate the uncompressed + * source image stored in srcImage 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 srcImage. + * + * @param y y offset (in pixels) of the region from which the JPEG image + * should be compressed, relative to the start of srcImage. + * + * @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 * width * TJ.pixelSize(pixelFormat) 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 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 width * * TJ.pixelSize(pixelFormat). * - * @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,8 +132,40 @@ public class TJCompressor { 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 @@ public class TJCompressor { 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 @@ public class TJCompressor { 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 @@ public class TJCompressor { 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 @@ public class TJCompressor { // 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 @@ public class TJCompressor { 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 c8920868..d7b032ae 100644 --- a/java/org_libjpegturbo_turbojpeg_TJ.h +++ b/java/org_libjpegturbo_turbojpeg_TJ.h @@ -55,6 +55,10 @@ extern "C" { #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 59f81e36..2fc91369 100644 --- a/java/org_libjpegturbo_turbojpeg_TJCompressor.h +++ b/java/org_libjpegturbo_turbojpeg_TJCompressor.h @@ -31,6 +31,14 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII (JNIEnv *, jobject, jbyteArray, jint, jint, jint, jint, jbyteArray, jint, jint, jint); +/* + * Class: org_libjpegturbo_turbojpeg_TJCompressor + * Method: compress + * Signature: ([BIIIIII[BIII)I + */ +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 @@ -39,6 +47,14 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII (JNIEnv *, jobject, jintArray, jint, jint, jint, jint, jbyteArray, jint, jint, jint); +/* + * 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 diff --git a/tjbenchtest.java.in b/tjbenchtest.java.in new file mode 100755 index 00000000..ebff9c84 --- /dev/null +++ b/tjbenchtest.java.in @@ -0,0 +1,179 @@ +#!/bin/bash + +set -u +set -e +trap onexit INT +trap onexit TERM +trap onexit EXIT + +onexit() +{ + if [ -d $OUTDIR ]; then + rm -rf $OUTDIR + fi +} + +runme() +{ + echo \*\*\* $* + $* +} + +IMAGES="vgl_5674_0098.bmp vgl_6434_0018a.bmp vgl_6548_0026a.bmp nightshot_iso_100.bmp" +IMGDIR=@srcdir@/testimages +OUTDIR=__tjbenchtest_java_output +EXEDIR=. +JAVA="@JAVA@ -cp java/turbojpeg.jar -Djava.library.path=.libs" + +if [ -d $OUTDIR ]; then + rm -rf $OUTDIR +fi +mkdir -p $OUTDIR + +exec >$EXEDIR/tjbenchtest-java.log + +# Standard tests +for image in $IMAGES; do + + cp $IMGDIR/$image $OUTDIR + basename=`basename $image .bmp` + $EXEDIR/cjpeg -quality 95 -dct fast -grayscale $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_GRAY_fast_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct fast -sample 2x2 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_420_fast_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct fast -sample 2x1 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_422_fast_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct fast -sample 1x1 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_444_fast_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct int -grayscale $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_GRAY_accurate_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct int -sample 2x2 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_420_accurate_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct int -sample 2x1 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_422_accurate_cjpeg.jpg + $EXEDIR/cjpeg -quality 95 -dct int -sample 1x1 $IMGDIR/${basename}.bmp >$OUTDIR/${basename}_444_accurate_cjpeg.jpg + for samp in GRAY 420 422 444; do + $EXEDIR/djpeg -rgb -bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg >$OUTDIR/${basename}_${samp}_default_djpeg.bmp + $EXEDIR/djpeg -dct fast -rgb -bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg >$OUTDIR/${basename}_${samp}_fast_djpeg.bmp + $EXEDIR/djpeg -dct int -rgb -bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg >$OUTDIR/${basename}_${samp}_accurate_djpeg.bmp + done + for samp in 420 422; do + $EXEDIR/djpeg -nosmooth -bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg >$OUTDIR/${basename}_${samp}_default_nosmooth_djpeg.bmp + $EXEDIR/djpeg -dct fast -nosmooth -bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg >$OUTDIR/${basename}_${samp}_fast_nosmooth_djpeg.bmp + $EXEDIR/djpeg -dct int -nosmooth -bmp $OUTDIR/${basename}_${samp}_accurate_cjpeg.jpg >$OUTDIR/${basename}_${samp}_accurate_nosmooth_djpeg.bmp + done + + # Compression + for dct in accurate fast; do + runme $JAVA TJBench $OUTDIR/$image 95 -rgb -quiet -benchtime 0.01 -${dct}dct + for samp in GRAY 420 422 444; do + runme cmp $OUTDIR/${basename}_${samp}_Q95.jpg $OUTDIR/${basename}_${samp}_${dct}_cjpeg.jpg + done + done + + for dct in fast accurate default; do + dctarg=-${dct}dct + if [ "${dct}" = "default" ]; then + dctarg= + fi + + # Tiled compression & decompression + runme $JAVA TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 ${dctarg} + for samp in GRAY 444; do + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp + rm $i + done + done + runme $JAVA TJBench $OUTDIR/$image 95 -rgb -tile -quiet -benchtime 0.01 -fastupsample ${dctarg} + for samp in 420 422; do + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp + rm $i + done + done + + # Tiled decompression + for samp in GRAY 444; do + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 ${dctarg} + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${dct}_djpeg.bmp + rm $i + done + done + for samp in 420 422; do + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -tile -quiet -benchtime 0.01 -fastupsample ${dctarg} + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp $i -i 54:54 $OUTDIR/${basename}_${samp}_${dct}_nosmooth_djpeg.bmp + rm $i + done + done + done + + # Scaled decompression + for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do + scalearg=`echo $scale | sed s@_@/@g` + for samp in GRAY 420 422 444; do + $EXEDIR/djpeg -rgb -scale ${scalearg} -bmp $OUTDIR/${basename}_${samp}_fast_cjpeg.jpg >$OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -scale ${scalearg} -quiet -benchtime 0.01 + runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${scale}_djpeg.bmp + rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp + done + done + + # Transforms + for samp in GRAY 420 422 444; do + $EXEDIR/jpegtran -flip horizontal -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_hflip_jpegtran.jpg + $EXEDIR/jpegtran -flip vertical -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_vflip_jpegtran.jpg + $EXEDIR/jpegtran -transpose -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_transpose_jpegtran.jpg + $EXEDIR/jpegtran -transverse -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_transverse_jpegtran.jpg + $EXEDIR/jpegtran -rotate 90 -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_rot90_jpegtran.jpg + $EXEDIR/jpegtran -rotate 180 -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_rot180_jpegtran.jpg + $EXEDIR/jpegtran -rotate 270 -trim $OUTDIR/${basename}_${samp}_Q95.jpg >$OUTDIR/${basename}_${samp}_rot270_jpegtran.jpg + done + for xform in hflip vflip transpose transverse rot90 rot180 rot270; do + for samp in GRAY 444; do + $EXEDIR/djpeg -rgb -bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg >$OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp + rm $i + done + done + for samp in 420 422; do + $EXEDIR/djpeg -nosmooth -rgb -bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg >$OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -fastupsample + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_${samp}_${xform}_jpegtran.bmp + rm $i + done + done + done + + # Grayscale transform + for xform in hflip vflip transpose transverse rot90 rot180 rot270; do + for samp in GRAY 444 422 420; do + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -tile -quiet -benchtime 0.01 -grayscale + for i in $OUTDIR/${basename}_${samp}_Q95_[0-9]*[0-9]x[0-9]*[0-9].bmp \ + $OUTDIR/${basename}_${samp}_Q95_full.bmp; do + runme cmp -i 54:54 $i $OUTDIR/${basename}_GRAY_${xform}_jpegtran.bmp + rm $i + done + done + done + + # Transforms with scaling + for xform in hflip vflip transpose transverse rot90 rot180 rot270; do + for samp in GRAY 444 422 420; do + for scale in 2_1 15_8 7_4 13_8 3_2 11_8 5_4 9_8 7_8 3_4 5_8 1_2 3_8 1_4 1_8; do + scalearg=`echo $scale | sed s@_@/@g` + $EXEDIR/djpeg -rgb -scale ${scalearg} -bmp $OUTDIR/${basename}_${samp}_${xform}_jpegtran.jpg >$OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp + runme $JAVA TJBench $OUTDIR/${basename}_${samp}_Q95.jpg -$xform -scale ${scalearg} -quiet -benchtime 0.01 + runme cmp -i 54:54 $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp $OUTDIR/${basename}_${samp}_${xform}_${scale}_jpegtran.bmp + rm $OUTDIR/${basename}_${samp}_Q95_${scale}.bmp + done + done + done + +done + +echo SUCCESS! diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c index c98845bd..d570ee9b 100644 --- a/turbojpeg-jni.c +++ b/turbojpeg-jni.c @@ -41,7 +41,16 @@ goto bailout; \ } -#define bailif0(f) {if(!(f)) goto bailout;} +#ifdef WIN32 +#define snprintf(str, n, format, ...) \ + _snprintf_s(str, n, _TRUNCATE, format, __VA_ARGS__) +#endif + +#define bailif0(f) {if(!(f)) { \ + char temps[80]; \ + snprintf(temps, 80, "Unexpected NULL condition in line %d", __LINE__); \ + _throw(temps); \ +}} #define gethandle() \ jclass _cls=(*env)->GetObjectClass(env, obj); \ @@ -88,13 +97,14 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init return; } -JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII - (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch, - jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, - jint flags) +JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII + (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width, + jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp, + jint jpegQual, jint flags) { tjhandle handle=0; - unsigned long jpegSize=0; jsize arraySize=0; + unsigned long jpegSize=0; + jsize arraySize=0, actualPitch; unsigned char *srcBuf=NULL, *jpegBuf=NULL; gethandle(); @@ -105,7 +115,8 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) _throw("Mismatch between Java and C API"); - arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height; + actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; + arraySize=(y+height-1)*actualPitch + x+width; if((*env)->GetArrayLength(env, src)GetPrimitiveArrayCritical(env, src, 0)); bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); - if(tjCompress2(handle, srcBuf, width, pitch, height, pf, &jpegBuf, - &jpegSize, jpegSubsamp, jpegQual, flags|TJFLAG_NOREALLOC)==-1) + if(tjCompress2(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]], width, + pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp, jpegQual, + flags|TJFLAG_NOREALLOC)==-1) + { + (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); + (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); + jpegBuf=srcBuf=NULL; + _throw(tjGetErrorStr()); + } + + bailout: + if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); + if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); + return (jint)jpegSize; +} + +JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII + (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch, + jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, + jint flags) +{ + return Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII( + env, obj, src, 0, 0, width, pitch, height, pf, dst, jpegSubsamp, jpegQual, + flags); +} + +JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII + (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width, + jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp, + jint jpegQual, jint flags) +{ + tjhandle handle=0; + unsigned long jpegSize=0; + jsize arraySize=0, actualStride; + unsigned char *srcBuf=NULL, *jpegBuf=NULL; + + gethandle(); + + if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 + || stride<0) + _throw("Invalid argument in compress()"); + if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) + _throw("Mismatch between Java and C API"); + if(tjPixelSize[pf]!=sizeof(jint)) + _throw("Pixel format must be 32-bit when compressing from an integer buffer."); + + actualStride=(stride==0)? width:stride; + arraySize=(y+height-1)*actualStride + x+width; + if((*env)->GetArrayLength(env, src)GetArrayLength(env, dst)<(jsize)jpegSize) + _throw("Destination buffer is not large enough"); + + bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); + bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); + + if(tjCompress2(handle, &srcBuf[(y*actualStride + x)*sizeof(int)], width, + stride*sizeof(jint), height, pf, &jpegBuf, &jpegSize, jpegSubsamp, + jpegQual, flags|TJFLAG_NOREALLOC)==-1) { (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); @@ -135,43 +204,9 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3 jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, jint flags) { - tjhandle handle=0; - unsigned long jpegSize=0; jsize arraySize=0; - unsigned char *srcBuf=NULL, *jpegBuf=NULL; - - gethandle(); - - if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 - || pitch<0) - _throw("Invalid argument in compress()"); - if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) - _throw("Mismatch between Java and C API"); - if(tjPixelSize[pf]!=sizeof(jint)) - _throw("Pixel format must be 32-bit when compressing from an integer buffer."); - - arraySize=(pitch==0)? width*height:pitch*height; - if((*env)->GetArrayLength(env, src)GetArrayLength(env, dst)<(jsize)jpegSize) - _throw("Destination buffer is not large enough"); - - bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); - bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); - - if(tjCompress2(handle, srcBuf, width, pitch*sizeof(jint), height, pf, - &jpegBuf, &jpegSize, jpegSubsamp, jpegQual, flags|TJFLAG_NOREALLOC)==-1) - { - (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); - (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); - jpegBuf=srcBuf=NULL; - _throw(tjGetErrorStr()); - } - - bailout: - if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); - if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); - return (jint)jpegSize; + return Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII( + env, obj, src, 0, 0, width, pitch, height, pf, dst, jpegSubsamp, jpegQual, + flags); } JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII diff --git a/turbojpeg-mapfile.jni b/turbojpeg-mapfile.jni index ce9463de..52184a3b 100755 --- a/turbojpeg-mapfile.jni +++ b/turbojpeg-mapfile.jni @@ -40,7 +40,9 @@ TURBOJPEG_1.2 Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors; Java_org_libjpegturbo_turbojpeg_TJCompressor_init; Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII; + Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII; Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII; + Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII; Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII; Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII; Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy;