| /* |
| * Copyright (C)2009-2014, 2016-2019, 2021-2023 D. R. Commander. |
| * All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * - 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.*; |
| import java.awt.image.*; |
| import javax.imageio.*; |
| import java.nio.*; |
| import java.util.*; |
| import org.libjpegturbo.turbojpeg.*; |
| |
| final class TJBench { |
| |
| private TJBench() {} |
| |
| private static boolean stopOnWarning, bottomUp, fastUpsample, fastDCT, |
| optimize, progressive, limitScans, arithmetic, lossless; |
| private static int maxMemory = 0, maxPixels = 0, precision = 8, quiet = 0, |
| pf = TJ.PF_BGR, yuvAlign = 1, restartIntervalBlocks, |
| restartIntervalRows = 0; |
| private static boolean compOnly, decompOnly, doTile, doYUV, write = true, |
| bmp = false; |
| |
| static final String[] PIXFORMATSTR = { |
| "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", |
| "CMYK" |
| }; |
| |
| static final String[] SUBNAME_LONG = { |
| "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1" |
| }; |
| |
| static final String[] SUBNAME = { |
| "444", "422", "420", "GRAY", "440", "411", "441" |
| }; |
| |
| static final String[] CSNAME = { |
| "RGB", "YCbCr", "GRAY", "CMYK", "YCCK" |
| }; |
| |
| private static TJScalingFactor sf = TJ.UNSCALED; |
| private static java.awt.Rectangle cr = TJ.UNCROPPED; |
| private static int xformOp = TJTransform.OP_NONE, xformOpt = 0; |
| private static double benchTime = 5.0, warmup = 1.0; |
| |
| |
| private static class DummyDCTFilter implements TJCustomFilter { |
| public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion, |
| Rectangle planeRegion, int componentID, |
| int transformID, TJTransform transform) { |
| for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) |
| coeffBuffer.put(i, (short)(-coeffBuffer.get(i))); |
| } |
| } |
| |
| private static DummyDCTFilter customFilter; |
| |
| |
| @SuppressWarnings("checkstyle:HiddenField") |
| private static boolean isCropped(java.awt.Rectangle cr) { |
| return (cr.x != 0 || cr.y != 0 || cr.width != 0 || cr.height != 0); |
| } |
| |
| private static int getCroppedWidth(int width) { |
| if (isCropped(cr)) |
| return (cr.width != 0 ? cr.width : sf.getScaled(width) - cr.x); |
| else |
| return sf.getScaled(width); |
| } |
| |
| private static int getCroppedHeight(int height) { |
| if (isCropped(cr)) |
| return (cr.height != 0 ? cr.height : sf.getScaled(height) - cr.y); |
| else |
| return sf.getScaled(height); |
| } |
| |
| |
| static double getTime() { |
| return (double)System.nanoTime() / 1.0e9; |
| } |
| |
| |
| private static String tjErrorMsg; |
| private static int tjErrorCode = -1; |
| |
| static void handleTJException(TJException e) throws TJException { |
| String errorMsg = e.getMessage(); |
| int errorCode = e.getErrorCode(); |
| |
| if (!stopOnWarning && errorCode == TJ.ERR_WARNING) { |
| if (tjErrorMsg == null || !tjErrorMsg.equals(errorMsg) || |
| tjErrorCode != errorCode) { |
| tjErrorMsg = errorMsg; |
| tjErrorCode = errorCode; |
| System.out.println("WARNING: " + errorMsg); |
| } |
| } else |
| throw e; |
| } |
| |
| |
| static String formatName(int subsamp, int cs) { |
| if (quiet != 0) { |
| if (lossless) |
| return String.format("%-2d/LOSSLESS ", precision); |
| else if (subsamp == TJ.SAMP_UNKNOWN) |
| return String.format("%-2d/%-5s ", precision, CSNAME[cs]); |
| else |
| return String.format("%-2d/%-5s/%-5s", precision, CSNAME[cs], |
| SUBNAME_LONG[subsamp]); |
| } else { |
| if (lossless) |
| return "Lossless"; |
| else if (subsamp == TJ.SAMP_UNKNOWN) |
| return CSNAME[cs]; |
| else |
| return CSNAME[cs] + " " + SUBNAME_LONG[subsamp]; |
| } |
| } |
| |
| |
| 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); |
| } |
| |
| |
| /* Decompression test */ |
| static void decomp(byte[][] jpegBufs, int[] jpegSizes, Object dstBuf, int w, |
| int h, int subsamp, int jpegQual, String fileName, |
| int tilew, int tileh) throws Exception { |
| String qualStr = new String(""), sizeStr, tempStr; |
| TJDecompressor tjd; |
| double elapsed, elapsedDecode; |
| int ps = TJ.getPixelSize(pf), i, iter = 0; |
| int scaledw, scaledh, pitch; |
| YUVImage yuvImage = null; |
| |
| if (lossless) |
| sf = TJ.UNSCALED; |
| |
| scaledw = sf.getScaled(w); |
| scaledh = sf.getScaled(h); |
| |
| if (jpegQual > 0) |
| qualStr = new String((lossless ? "_PSV" : "_Q") + jpegQual); |
| |
| tjd = new TJDecompressor(); |
| tjd.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0); |
| tjd.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0); |
| tjd.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0); |
| tjd.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0); |
| tjd.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0); |
| tjd.set(TJ.PARAM_MAXMEMORY, maxMemory); |
| tjd.set(TJ.PARAM_MAXPIXELS, maxPixels); |
| |
| if (isCropped(cr)) { |
| try { |
| tjd.setSourceImage(jpegBufs[0], jpegSizes[0]); |
| } catch (TJException e) { handleTJException(e); } |
| } |
| tjd.setScalingFactor(sf); |
| tjd.setCroppingRegion(cr); |
| if (isCropped(cr)) { |
| scaledw = cr.width != 0 ? cr.width : scaledw - cr.x; |
| scaledh = cr.height != 0 ? cr.height : scaledh - cr.y; |
| } |
| pitch = scaledw * ps; |
| |
| if (dstBuf == null) { |
| if ((long)pitch * (long)scaledh > (long)Integer.MAX_VALUE) |
| throw new Exception("Image is too large"); |
| if (precision == 8) |
| dstBuf = new byte[pitch * scaledh]; |
| else |
| dstBuf = new short[pitch * scaledh]; |
| } |
| |
| /* Set the destination buffer to gray so we know whether the decompressor |
| attempted to write to it */ |
| if (precision == 8) |
| Arrays.fill((byte[])dstBuf, (byte)127); |
| else if (precision == 12) |
| Arrays.fill((short[])dstBuf, (short)2047); |
| else |
| Arrays.fill((short[])dstBuf, (short)32767); |
| |
| if (doYUV) { |
| int width = doTile ? tilew : scaledw; |
| int height = doTile ? tileh : scaledh; |
| |
| yuvImage = new YUVImage(width, yuvAlign, height, subsamp); |
| Arrays.fill(yuvImage.getBuf(), (byte)127); |
| } |
| |
| /* Benchmark */ |
| iter = -1; |
| elapsed = elapsedDecode = 0.0; |
| while (true) { |
| int tile = 0; |
| double start = getTime(); |
| |
| 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; |
| |
| try { |
| tjd.setSourceImage(jpegBufs[tile], jpegSizes[tile]); |
| } catch (TJException e) { handleTJException(e); } |
| if (doYUV) { |
| yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height, |
| subsamp); |
| try { |
| tjd.decompressToYUV(yuvImage); |
| } catch (TJException e) { handleTJException(e); } |
| double startDecode = getTime(); |
| tjd.setSourceImage(yuvImage); |
| try { |
| tjd.decompress8((byte[])dstBuf, x, y, pitch, pf); |
| } catch (TJException e) { handleTJException(e); } |
| if (iter >= 0) |
| elapsedDecode += getTime() - startDecode; |
| } else { |
| try { |
| if (precision == 8) |
| tjd.decompress8((byte[])dstBuf, x, y, pitch, pf); |
| else if (precision == 12) |
| tjd.decompress12((short[])dstBuf, x, y, pitch, pf); |
| else |
| tjd.decompress16((short[])dstBuf, x, y, pitch, pf); |
| } catch (TJException e) { handleTJException(e); } |
| } |
| } |
| } |
| elapsed += getTime() - start; |
| if (iter >= 0) { |
| iter++; |
| if (elapsed >= benchTime) |
| break; |
| } else if (elapsed >= warmup) { |
| iter = 0; |
| elapsed = elapsedDecode = 0.0; |
| } |
| } |
| if (doYUV) |
| elapsed -= elapsedDecode; |
| |
| for (i = 0; i < jpegBufs.length; i++) |
| jpegBufs[i] = null; |
| jpegBufs = null; jpegSizes = null; |
| System.gc(); |
| |
| if (quiet != 0) { |
| System.out.format("%-6s%s", |
| sigFig((double)(w * h) / 1000000. * |
| (double)iter / elapsed, 4), |
| quiet == 2 ? "\n" : " "); |
| if (doYUV) |
| System.out.format("%s\n", |
| sigFig((double)(w * h) / 1000000. * |
| (double)iter / elapsedDecode, 4)); |
| else if (quiet != 2) |
| System.out.print("\n"); |
| } else { |
| System.out.format("%s --> Frame rate: %f fps\n", |
| (doYUV ? "Decomp to YUV" : "Decompress "), |
| (double)iter / elapsed); |
| System.out.format(" Throughput: %f Megapixels/sec\n", |
| (double)(w * h) / 1000000. * (double)iter / elapsed); |
| if (doYUV) { |
| System.out.format("YUV Decode --> Frame rate: %f fps\n", |
| (double)iter / elapsedDecode); |
| System.out.format(" Throughput: %f Megapixels/sec\n", |
| (double)(w * h) / 1000000. * |
| (double)iter / elapsedDecode); |
| } |
| } |
| |
| if (!write) return; |
| |
| 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 ? ".bmp" : ".ppm")); |
| else |
| tempStr = new String(fileName + "_" + |
| (lossless ? "LOSSLS" : SUBNAME[subsamp]) + qualStr + |
| "_" + sizeStr + (bmp ? ".bmp" : ".ppm")); |
| |
| tjd.saveImage(precision, tempStr, dstBuf, scaledw, 0, scaledh, pf); |
| } |
| |
| |
| static void fullTest(TJCompressor tjc, Object srcBuf, int w, int h, |
| int subsamp, int jpegQual, String fileName) |
| throws Exception { |
| Object tmpBuf; |
| byte[][] jpegBufs; |
| int[] jpegSizes; |
| double start, elapsed, elapsedEncode; |
| int totalJpegSize = 0, tilew, tileh, i, iter; |
| int ps = TJ.getPixelSize(pf); |
| int ntilesw = 1, ntilesh = 1, pitch = w * ps; |
| String pfStr = PIXFORMATSTR[pf]; |
| YUVImage yuvImage = null; |
| |
| if ((long)pitch * (long)h > (long)Integer.MAX_VALUE) |
| throw new Exception("Image is too large"); |
| if (precision == 8) |
| tmpBuf = new byte[pitch * h]; |
| else |
| tmpBuf = new short[pitch * h]; |
| |
| if (quiet == 0) |
| System.out.format(">>>>> %s (%s) <--> %d-bit JPEG (%s %s%d) <<<<<\n", |
| pfStr, bottomUp ? "Bottom-up" : "Top-down", precision, |
| lossless ? "Lossless" : SUBNAME_LONG[subsamp], |
| lossless ? "PSV" : "Q", jpegQual); |
| |
| tjc.set(TJ.PARAM_SUBSAMP, subsamp); |
| tjc.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0); |
| tjc.set(TJ.PARAM_OPTIMIZE, optimize ? 1 : 0); |
| tjc.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0); |
| tjc.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0); |
| tjc.set(TJ.PARAM_LOSSLESS, lossless ? 1 : 0); |
| if (lossless) |
| tjc.set(TJ.PARAM_LOSSLESSPSV, jpegQual); |
| else |
| tjc.set(TJ.PARAM_QUALITY, jpegQual); |
| tjc.set(TJ.PARAM_RESTARTBLOCKS, restartIntervalBlocks); |
| tjc.set(TJ.PARAM_RESTARTROWS, restartIntervalRows); |
| tjc.set(TJ.PARAM_MAXMEMORY, maxMemory); |
| |
| 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; |
| |
| jpegBufs = |
| new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)]; |
| jpegSizes = new int[ntilesw * ntilesh]; |
| |
| /* Compression test */ |
| if (quiet == 1) |
| System.out.format("%-4s(%s) %-2d/%-6s %-3d ", pfStr, |
| bottomUp ? "BU" : "TD", precision, |
| lossless ? "LOSSLS" : SUBNAME_LONG[subsamp], |
| jpegQual); |
| if (precision == 8) { |
| for (i = 0; i < h; i++) |
| System.arraycopy((byte[])srcBuf, w * ps * i, (byte[])tmpBuf, |
| pitch * i, w * ps); |
| } else { |
| for (i = 0; i < h; i++) |
| System.arraycopy((short[])srcBuf, w * ps * i, (short[])tmpBuf, |
| pitch * i, w * ps); |
| } |
| |
| if (doYUV) { |
| yuvImage = new YUVImage(tilew, yuvAlign, tileh, subsamp); |
| Arrays.fill(yuvImage.getBuf(), (byte)127); |
| } |
| |
| /* Benchmark */ |
| iter = -1; |
| elapsed = elapsedEncode = 0.0; |
| while (true) { |
| int tile = 0; |
| |
| totalJpegSize = 0; |
| start = getTime(); |
| 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); |
| |
| if (precision == 8) |
| tjc.setSourceImage((byte[])srcBuf, x, y, width, pitch, height, |
| pf); |
| else if (precision == 12) |
| tjc.setSourceImage12((short[])srcBuf, x, y, width, pitch, height, |
| pf); |
| else |
| tjc.setSourceImage16((short[])srcBuf, x, y, width, pitch, height, |
| pf); |
| if (doYUV) { |
| double startEncode = getTime(); |
| |
| yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height, |
| subsamp); |
| tjc.encodeYUV(yuvImage); |
| if (iter >= 0) |
| elapsedEncode += getTime() - startEncode; |
| tjc.setSourceImage(yuvImage); |
| } |
| tjc.compress(jpegBufs[tile]); |
| jpegSizes[tile] = tjc.getCompressedSize(); |
| totalJpegSize += jpegSizes[tile]; |
| } |
| } |
| elapsed += getTime() - start; |
| if (iter >= 0) { |
| iter++; |
| if (elapsed >= benchTime) |
| break; |
| } else if (elapsed >= warmup) { |
| iter = 0; |
| elapsed = elapsedEncode = 0.0; |
| } |
| } |
| if (doYUV) |
| elapsed -= elapsedEncode; |
| |
| if (quiet == 1) |
| System.out.format("%-5d %-5d ", tilew, tileh); |
| if (quiet != 0) { |
| if (doYUV) |
| System.out.format("%-6s%s", |
| sigFig((double)(w * h) / 1000000. * |
| (double)iter / elapsedEncode, 4), |
| quiet == 2 ? "\n" : " "); |
| System.out.format("%-6s%s", |
| sigFig((double)(w * h) / 1000000. * |
| (double)iter / elapsed, 4), |
| quiet == 2 ? "\n" : " "); |
| System.out.format("%-6s%s", |
| sigFig((double)(w * h * ps) / (double)totalJpegSize, |
| 4), |
| quiet == 2 ? "\n" : " "); |
| } else { |
| System.out.format("\n%s size: %d x %d\n", doTile ? "Tile" : "Image", |
| tilew, tileh); |
| if (doYUV) { |
| System.out.format("Encode YUV --> Frame rate: %f fps\n", |
| (double)iter / elapsedEncode); |
| System.out.format(" Output image size: %d bytes\n", |
| yuvImage.getSize()); |
| System.out.format(" Compression ratio: %f:1\n", |
| (double)(w * h * ps) / (double)yuvImage.getSize()); |
| System.out.format(" Throughput: %f Megapixels/sec\n", |
| (double)(w * h) / 1000000. * |
| (double)iter / elapsedEncode); |
| System.out.format(" Output bit stream: %f Megabits/sec\n", |
| (double)yuvImage.getSize() * 8. / 1000000. * |
| (double)iter / elapsedEncode); |
| } |
| System.out.format("%s --> Frame rate: %f fps\n", |
| doYUV ? "Comp from YUV" : "Compress ", |
| (double)iter / 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(" Throughput: %f Megapixels/sec\n", |
| (double)(w * h) / 1000000. * (double)iter / elapsed); |
| System.out.format(" Output bit stream: %f Megabits/sec\n", |
| (double)totalJpegSize * 8. / 1000000. * |
| (double)iter / elapsed); |
| } |
| if (tilew == w && tileh == h && write) { |
| String tempStr = fileName + "_" + |
| (lossless ? "LOSSLS" : SUBNAME[subsamp]) + "_" + |
| (lossless ? "PSV" : "Q") + jpegQual + ".jpg"; |
| FileOutputStream fos = new FileOutputStream(tempStr); |
| |
| fos.write(jpegBufs[0], 0, jpegSizes[0]); |
| fos.close(); |
| if (quiet == 0) |
| System.out.println("Reference image written to " + tempStr); |
| } |
| |
| /* Decompression test */ |
| if (!compOnly) |
| decomp(jpegBufs, jpegSizes, tmpBuf, w, h, subsamp, jpegQual, fileName, |
| tilew, tileh); |
| else if (quiet == 1) |
| System.out.println("N/A"); |
| |
| if (tilew == w && tileh == h) break; |
| } |
| } |
| |
| |
| static void decompTest(String fileName) throws Exception { |
| TJTransformer tjt; |
| byte[][] jpegBufs = null; |
| byte[] srcBuf; |
| int[] jpegSizes = null; |
| int totalJpegSize; |
| double start, elapsed; |
| int ps = TJ.getPixelSize(pf), tile, x, y, iter; |
| // Original image |
| int w = 0, h = 0, ntilesw = 1, ntilesh = 1, subsamp = -1, cs = -1; |
| // Transformed image |
| int minTile = 16, tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp; |
| |
| FileInputStream fis = new FileInputStream(fileName); |
| if (fis.getChannel().size() > (long)Integer.MAX_VALUE) |
| throw new Exception("Image is too large"); |
| int srcSize = (int)fis.getChannel().size(); |
| srcBuf = new byte[srcSize]; |
| fis.read(srcBuf, 0, srcSize); |
| fis.close(); |
| |
| int index = fileName.lastIndexOf('.'); |
| if (index >= 0) |
| fileName = new String(fileName.substring(0, index)); |
| |
| tjt = new TJTransformer(); |
| tjt.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0); |
| tjt.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0); |
| tjt.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0); |
| tjt.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0); |
| tjt.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0); |
| tjt.set(TJ.PARAM_MAXMEMORY, maxMemory); |
| tjt.set(TJ.PARAM_MAXPIXELS, maxPixels); |
| |
| try { |
| tjt.setSourceImage(srcBuf, srcSize); |
| } catch (TJException e) { handleTJException(e); } |
| w = tjt.getWidth(); |
| h = tjt.getHeight(); |
| subsamp = tjt.get(TJ.PARAM_SUBSAMP); |
| precision = tjt.get(TJ.PARAM_PRECISION); |
| cs = tjt.get(TJ.PARAM_COLORSPACE); |
| if (tjt.get(TJ.PARAM_PROGRESSIVE) == 1) |
| System.out.println("JPEG image uses progressive entropy coding\n"); |
| if (tjt.get(TJ.PARAM_ARITHMETIC) == 1) |
| System.out.println("JPEG image uses arithmetic entropy coding\n"); |
| tjt.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0); |
| tjt.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0); |
| |
| if (cs == TJ.CS_YCCK || cs == TJ.CS_CMYK) { |
| pf = TJ.PF_CMYK; ps = TJ.getPixelSize(pf); |
| } |
| |
| if (tjt.get(TJ.PARAM_LOSSLESS) != 0) |
| sf = TJ.UNSCALED; |
| |
| tjt.setScalingFactor(sf); |
| tjt.setCroppingRegion(cr); |
| |
| if (quiet == 1) { |
| System.out.println("All performance values in Mpixels/sec\n"); |
| System.out.format("Pixel JPEG %s %s Xform Comp Decomp ", |
| (doTile ? "Tile " : "Image"), |
| (doTile ? "Tile " : "Image")); |
| if (doYUV) |
| System.out.print("Decode"); |
| System.out.print("\n"); |
| System.out.print("Format Format Width Height Perf Ratio Perf "); |
| if (doYUV) |
| System.out.print("Perf"); |
| System.out.println("\n"); |
| } else if (quiet == 0) |
| System.out.format(">>>>> %d-bit JPEG (%s) --> %s (%s) <<<<<\n", |
| precision, formatName(subsamp, cs), PIXFORMATSTR[pf], |
| bottomUp ? "Bottom-up" : "Top-down"); |
| |
| if (doTile) { |
| if (subsamp == TJ.SAMP_UNKNOWN) |
| throw new Exception("Could not determine subsampling level of JPEG image"); |
| minTile = Math.max(TJ.getMCUWidth(subsamp), TJ.getMCUHeight(subsamp)); |
| } |
| for (int tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ; |
| tilew *= 2, tileh *= 2) { |
| if (tilew > w) |
| tilew = w; |
| if (tileh > h) |
| tileh = h; |
| ntilesw = (w + tilew - 1) / tilew; |
| ntilesh = (h + tileh - 1) / tileh; |
| |
| tw = w; th = h; ttilew = tilew; ttileh = tileh; |
| if (quiet == 0) { |
| System.out.format("\n%s size: %d x %d", (doTile ? "Tile" : "Image"), |
| ttilew, ttileh); |
| if (sf.getNum() != 1 || sf.getDenom() != 1 || isCropped(cr)) |
| System.out.format(" --> %d x %d", getCroppedWidth(tw), |
| getCroppedHeight(th)); |
| System.out.println(""); |
| } else if (quiet == 1) { |
| System.out.format("%-4s(%s) %-14s ", PIXFORMATSTR[pf], |
| bottomUp ? "BU" : "TD", formatName(subsamp, cs)); |
| System.out.format("%-5d %-5d ", getCroppedWidth(tilew), |
| getCroppedHeight(tileh)); |
| } |
| |
| tsubsamp = subsamp; |
| if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0 || |
| customFilter != null) { |
| if (xformOp == TJTransform.OP_TRANSPOSE || |
| xformOp == TJTransform.OP_TRANSVERSE || |
| xformOp == TJTransform.OP_ROT90 || |
| xformOp == TJTransform.OP_ROT270) { |
| tw = h; th = w; ttilew = tileh; ttileh = tilew; |
| } |
| |
| if (xformOp != TJTransform.OP_NONE && |
| xformOp != TJTransform.OP_TRANSPOSE && subsamp == TJ.SAMP_UNKNOWN) |
| throw new Exception("Could not determine subsampling level of JPEG image"); |
| if ((xformOpt & TJTransform.OPT_GRAY) != 0) |
| tsubsamp = TJ.SAMP_GRAY; |
| if (xformOp == TJTransform.OP_HFLIP || |
| xformOp == TJTransform.OP_ROT180) |
| tw = tw - (tw % TJ.getMCUWidth(tsubsamp)); |
| if (xformOp == TJTransform.OP_VFLIP || |
| xformOp == TJTransform.OP_ROT180) |
| th = th - (th % TJ.getMCUHeight(tsubsamp)); |
| if (xformOp == TJTransform.OP_TRANSVERSE || |
| xformOp == TJTransform.OP_ROT90) |
| tw = tw - (tw % TJ.getMCUHeight(tsubsamp)); |
| if (xformOp == TJTransform.OP_TRANSVERSE || |
| xformOp == TJTransform.OP_ROT270) |
| th = th - (th % TJ.getMCUWidth(tsubsamp)); |
| tntilesw = (tw + ttilew - 1) / ttilew; |
| tntilesh = (th + ttileh - 1) / ttileh; |
| |
| if (xformOp == TJTransform.OP_TRANSPOSE || |
| xformOp == TJTransform.OP_TRANSVERSE || |
| xformOp == TJTransform.OP_ROT90 || |
| xformOp == TJTransform.OP_ROT270) { |
| if (tsubsamp == TJ.SAMP_422) |
| tsubsamp = TJ.SAMP_440; |
| else if (tsubsamp == TJ.SAMP_440) |
| tsubsamp = TJ.SAMP_422; |
| else if (tsubsamp == TJ.SAMP_411) |
| tsubsamp = TJ.SAMP_441; |
| else if (tsubsamp == TJ.SAMP_441) |
| tsubsamp = TJ.SAMP_411; |
| } |
| |
| TJTransform[] t = new TJTransform[tntilesw * tntilesh]; |
| jpegBufs = |
| new byte[tntilesw * tntilesh][TJ.bufSize(ttilew, ttileh, subsamp)]; |
| |
| for (y = 0, tile = 0; y < th; y += ttileh) { |
| for (x = 0; x < tw; x += ttilew, tile++) { |
| t[tile] = new TJTransform(); |
| t[tile].width = Math.min(ttilew, tw - x); |
| t[tile].height = Math.min(ttileh, th - y); |
| t[tile].x = x; |
| t[tile].y = y; |
| t[tile].op = xformOp; |
| t[tile].options = xformOpt | TJTransform.OPT_TRIM; |
| t[tile].cf = customFilter; |
| if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 && |
| jpegBufs[tile] != null) |
| jpegBufs[tile] = null; |
| } |
| } |
| |
| iter = -1; |
| elapsed = 0.; |
| while (true) { |
| start = getTime(); |
| try { |
| tjt.transform(jpegBufs, t); |
| } catch (TJException e) { handleTJException(e); } |
| jpegSizes = tjt.getTransformedSizes(); |
| elapsed += getTime() - start; |
| if (iter >= 0) { |
| iter++; |
| if (elapsed >= benchTime) |
| break; |
| } else if (elapsed >= warmup) { |
| iter = 0; |
| elapsed = 0.0; |
| } |
| } |
| t = null; |
| |
| for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++) |
| totalJpegSize += jpegSizes[tile]; |
| |
| if (quiet != 0) { |
| System.out.format("%-6s%s%-6s%s", |
| sigFig((double)(w * h) / 1000000. / elapsed, 4), |
| quiet == 2 ? "\n" : " ", |
| sigFig((double)(w * h * ps) / |
| (double)totalJpegSize, 4), |
| quiet == 2 ? "\n" : " "); |
| } else { |
| System.out.format("Transform --> Frame rate: %f fps\n", |
| 1.0 / 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(" 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 N/A "); |
| jpegBufs = new byte[1][TJ.bufSize(ttilew, ttileh, subsamp)]; |
| jpegSizes = new int[1]; |
| jpegBufs[0] = srcBuf; |
| jpegSizes[0] = srcSize; |
| } |
| |
| if (w == tilew) |
| ttilew = tw; |
| if (h == tileh) |
| ttileh = th; |
| if ((xformOpt & TJTransform.OPT_NOOUTPUT) == 0) |
| decomp(jpegBufs, jpegSizes, null, tw, th, tsubsamp, 0, fileName, |
| ttilew, ttileh); |
| else if (quiet == 1) |
| System.out.println("N/A"); |
| |
| jpegBufs = null; |
| jpegSizes = 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(" <Inputimage (BMP|PPM)> <Quality or PSV> [options]\n"); |
| System.out.println(" java " + className); |
| System.out.println(" <Inputimage (JPG)> [options]"); |
| |
| System.out.println("\nGENERAL OPTIONS"); |
| System.out.println("---------------"); |
| System.out.println("-benchtime T = Run each benchmark for at least T seconds [default = 5.0]"); |
| System.out.println("-bmp = Use Windows Bitmap format for output images [default = PPM]"); |
| System.out.println(" ** 8-bit data precision only **"); |
| System.out.println("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers"); |
| System.out.println("-componly = Stop after running compression tests. Do not test decompression."); |
| System.out.println("-lossless = Generate lossless JPEG images when compressing (implies"); |
| System.out.println(" -subsamp 444). PSV is the predictor selection value (1-7)."); |
| System.out.println("-maxmemory = Memory limit (in megabytes) for intermediate buffers used with"); |
| System.out.println(" progressive JPEG compression and decompression, optimized baseline entropy"); |
| System.out.println(" coding, lossless JPEG compression, and lossless transformation"); |
| System.out.println(" [default = no limit]"); |
| System.out.println("-maxpixels = Input image size limit (in pixels) [default = no limit]"); |
| System.out.println("-nowrite = Do not write reference or output images (improves consistency of"); |
| System.out.println(" benchmark results)"); |
| System.out.println("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb ="); |
| System.out.println(" Use the specified pixel format for packed-pixel source/destination buffers"); |
| System.out.println(" [default = BGR]"); |
| System.out.println("-cmyk = Indirectly test YCCK JPEG compression/decompression"); |
| System.out.println(" (use the CMYK pixel format for packed-pixel source/destination buffers)"); |
| System.out.println("-precision N = Use N-bit data precision when compressing [N is 8, 12, or 16;"); |
| System.out.println(" default = 8; if N is 16, then -lossless must also be specified]"); |
| System.out.println(" (-precision 12 implies -optimize unless -arithmetic is also specified)"); |
| System.out.println("-quiet = Output results in tabular rather than verbose format"); |
| System.out.println("-restart N = When compressing, add a restart marker every N MCU rows (lossy) or"); |
| System.out.println(" N sample rows (lossless) [default = 0 (no restart markers)]. Append 'B'"); |
| System.out.println(" to specify the restart marker interval in MCU blocks (lossy) or samples"); |
| System.out.println(" (lossless)."); |
| System.out.println("-stoponwarning = Immediately discontinue the current"); |
| System.out.println(" compression/decompression/transform operation if a warning (non-fatal"); |
| System.out.println(" error) occurs"); |
| System.out.println("-tile = Compress/transform the input image into separate JPEG tiles of varying"); |
| System.out.println(" sizes (useful for measuring JPEG overhead)"); |
| System.out.println("-warmup T = Run each benchmark for T seconds [default = 1.0] prior to starting"); |
| System.out.println(" the timer, in order to prime the caches and thus improve the consistency"); |
| System.out.println(" of the benchmark results"); |
| |
| System.out.println("\nLOSSY JPEG OPTIONS"); |
| System.out.println("------------------"); |
| System.out.println("-arithmetic = Use arithmetic entropy coding in JPEG images generated by"); |
| System.out.println(" compression and transform operations (can be combined with -progressive)"); |
| System.out.println("-crop WxH+X+Y = Decompress only the specified region of the JPEG image, where W"); |
| System.out.println(" and H are the width and height of the region (0 = maximum possible width"); |
| System.out.println(" or height) and X and Y are the left and upper boundary of the region, all"); |
| System.out.println(" specified relative to the scaled image dimensions. X must be divible by"); |
| System.out.println(" the scaled MCU width."); |
| System.out.println("-fastdct = Use the fastest DCT/IDCT algorithm available"); |
| System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available"); |
| System.out.println("-optimize = Use optimized baseline entropy coding in JPEG images generated by"); |
| System.out.println(" compession and transform operations"); |
| System.out.println("-progressive = Use progressive entropy coding in JPEG images generated by"); |
| System.out.println(" compression and transform operations (can be combined with -arithmetic;"); |
| System.out.println(" implies -optimize unless -arithmetic is also specified)"); |
| System.out.println("-limitscans = Refuse to decompress or transform progressive JPEG images that"); |
| System.out.println(" have an unreasonably large number of scans"); |
| System.out.println("-scale M/N = When decompressing, scale the width/height of the JPEG image by a"); |
| System.out.print(" factor of M/N (M/N = "); |
| for (i = 0; i < nsf; i++) { |
| System.out.format("%d/%d", scalingFactors[i].getNum(), |
| 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("-subsamp S = When compressing, use the specified level of chrominance"); |
| System.out.println(" subsampling (S = 444, 422, 440, 420, 411, 441, or GRAY) [default = test"); |
| System.out.println(" Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]"); |
| System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 ="); |
| System.out.println(" Perform the specified lossless transform operation on the input image"); |
| System.out.println(" prior to decompression (these operations are mutually exclusive)"); |
| System.out.println("-grayscale = Transform the input image into a grayscale JPEG image prior to"); |
| System.out.println(" decompression (can be combined with the other transform operations above)"); |
| System.out.println("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)"); |
| System.out.println(" when transforming the input image"); |
| System.out.println("-yuv = Compress from/decompress to intermediate planar YUV images"); |
| System.out.println(" ** 8-bit data precision only **"); |
| System.out.println("-yuvpad N = The number of bytes by which each row in each plane of an"); |
| System.out.println(" intermediate YUV image is evenly divisible (N must be a power of 2)"); |
| System.out.println(" [default = 1]"); |
| |
| System.out.println("\nNOTE: If the quality/PSV is specified as a range (e.g. 90-100 or 1-4), a"); |
| System.out.println("separate test will be performed for all values in the range.\n"); |
| System.exit(1); |
| } |
| |
| |
| public static void main(String[] argv) { |
| Object srcBuf = null; |
| int w = 0, h = 0, minQual = -1, maxQual = -1; |
| int minArg = 1, retval = 0; |
| int subsamp = -1; |
| TJCompressor tjc = null; |
| |
| try { |
| |
| if (argv.length < minArg) |
| usage(); |
| |
| String tempStr = argv[0].toLowerCase(); |
| if (tempStr.endsWith(".jpg") || tempStr.endsWith(".jpeg")) |
| decompOnly = true; |
| if (tempStr.endsWith(".bmp")) |
| bmp = true; |
| |
| System.out.println(""); |
| |
| if (!decompOnly) { |
| minArg = 2; |
| if (argv.length < minArg) |
| usage(); |
| String[] quals = argv[1].split("-", 2); |
| try { |
| minQual = Integer.parseInt(quals[0]); |
| } catch (NumberFormatException e) {} |
| if (quals.length > 1) { |
| try { |
| maxQual = Integer.parseInt(quals[1]); |
| } catch (NumberFormatException e) {} |
| } |
| if (maxQual < minQual) |
| 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; |
| } else if (argv[i].equalsIgnoreCase("-precision") && |
| i < argv.length - 1) { |
| int temp = 0; |
| |
| try { |
| temp = Integer.parseInt(argv[++i]); |
| } catch (NumberFormatException e) {} |
| if (temp == 8 || temp == 12 || temp == 16) |
| precision = temp; |
| else |
| usage(); |
| } else if (argv[i].equalsIgnoreCase("-fastupsample")) { |
| System.out.println("Using fastest upsampling algorithm\n"); |
| fastUpsample = true; |
| } else if (argv[i].equalsIgnoreCase("-fastdct")) { |
| System.out.println("Using fastest DCT/IDCT algorithm\n"); |
| fastDCT = true; |
| } else if (argv[i].equalsIgnoreCase("-optimize")) { |
| System.out.println("Using optimized baseline entropy coding\n"); |
| optimize = true; |
| xformOpt |= TJTransform.OPT_OPTIMIZE; |
| } else if (argv[i].equalsIgnoreCase("-progressive")) { |
| System.out.println("Using progressive entropy coding\n"); |
| progressive = true; |
| xformOpt |= TJTransform.OPT_PROGRESSIVE; |
| } else if (argv[i].equalsIgnoreCase("-arithmetic")) { |
| System.out.println("Using arithmetic entropy coding\n"); |
| arithmetic = true; |
| xformOpt |= TJTransform.OPT_ARITHMETIC; |
| } else if (argv[i].equalsIgnoreCase("-lossless")) { |
| lossless = true; |
| subsamp = TJ.SAMP_444; |
| } else if (argv[i].equalsIgnoreCase("-rgb")) |
| pf = TJ.PF_RGB; |
| else if (argv[i].equalsIgnoreCase("-rgbx")) |
| pf = TJ.PF_RGBX; |
| else if (argv[i].equalsIgnoreCase("-bgr")) |
| pf = TJ.PF_BGR; |
| else if (argv[i].equalsIgnoreCase("-bgrx")) |
| pf = TJ.PF_BGRX; |
| else if (argv[i].equalsIgnoreCase("-xbgr")) |
| pf = TJ.PF_XBGR; |
| else if (argv[i].equalsIgnoreCase("-xrgb")) |
| pf = TJ.PF_XRGB; |
| else if (argv[i].equalsIgnoreCase("-cmyk")) |
| pf = TJ.PF_CMYK; |
| else if (argv[i].equalsIgnoreCase("-bottomup")) |
| bottomUp = true; |
| else if (argv[i].equalsIgnoreCase("-quiet")) |
| quiet = 1; |
| else if (argv[i].equalsIgnoreCase("-qq")) |
| quiet = 2; |
| else 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(); |
| } else if (argv[i].equalsIgnoreCase("-crop") && |
| i < argv.length - 1) { |
| int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1; |
| Scanner scanner = new Scanner(argv[++i]).useDelimiter("x|\\+"); |
| |
| try { |
| temp1 = scanner.nextInt(); |
| temp2 = scanner.nextInt(); |
| temp3 = scanner.nextInt(); |
| temp4 = scanner.nextInt(); |
| } catch (Exception e) {} |
| |
| if (temp1 < 0 || temp2 < 0 || temp3 < 0 || temp4 < 0) |
| usage(); |
| cr.width = temp1; cr.height = temp2; cr.x = temp3; cr.y = temp4; |
| } else if (argv[i].equalsIgnoreCase("-hflip")) |
| xformOp = TJTransform.OP_HFLIP; |
| else if (argv[i].equalsIgnoreCase("-vflip")) |
| xformOp = TJTransform.OP_VFLIP; |
| else if (argv[i].equalsIgnoreCase("-transpose")) |
| xformOp = TJTransform.OP_TRANSPOSE; |
| else if (argv[i].equalsIgnoreCase("-transverse")) |
| xformOp = TJTransform.OP_TRANSVERSE; |
| else if (argv[i].equalsIgnoreCase("-rot90")) |
| xformOp = TJTransform.OP_ROT90; |
| else if (argv[i].equalsIgnoreCase("-rot180")) |
| xformOp = TJTransform.OP_ROT180; |
| else if (argv[i].equalsIgnoreCase("-rot270")) |
| xformOp = TJTransform.OP_ROT270; |
| else if (argv[i].equalsIgnoreCase("-grayscale")) |
| xformOpt |= TJTransform.OPT_GRAY; |
| else if (argv[i].equalsIgnoreCase("-custom")) |
| customFilter = new DummyDCTFilter(); |
| else if (argv[i].equalsIgnoreCase("-nooutput")) |
| xformOpt |= TJTransform.OPT_NOOUTPUT; |
| else if (argv[i].equalsIgnoreCase("-copynone")) |
| xformOpt |= TJTransform.OPT_COPYNONE; |
| else 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(); |
| } else if (argv[i].equalsIgnoreCase("-warmup") && |
| i < argv.length - 1) { |
| double temp = -1; |
| |
| try { |
| temp = Double.parseDouble(argv[++i]); |
| } catch (NumberFormatException e) {} |
| if (temp >= 0.0) { |
| warmup = temp; |
| System.out.format("Warmup time = %.1f seconds\n\n", warmup); |
| } else |
| usage(); |
| } else if (argv[i].equalsIgnoreCase("-bmp")) |
| bmp = true; |
| else if (argv[i].equalsIgnoreCase("-yuv")) { |
| System.out.println("Testing planar YUV encoding/decoding\n"); |
| doYUV = true; |
| } else if (argv[i].equalsIgnoreCase("-yuvpad") && |
| i < argv.length - 1) { |
| int temp = 0; |
| |
| try { |
| temp = Integer.parseInt(argv[++i]); |
| } catch (NumberFormatException e) {} |
| if (temp >= 1 && (temp & (temp - 1)) == 0) |
| yuvAlign = temp; |
| else |
| usage(); |
| } else if (argv[i].equalsIgnoreCase("-subsamp") && |
| i < argv.length - 1) { |
| i++; |
| if (argv[i].toUpperCase().startsWith("G")) |
| subsamp = TJ.SAMP_GRAY; |
| else if (argv[i].equals("444")) |
| subsamp = TJ.SAMP_444; |
| else if (argv[i].equals("422")) |
| subsamp = TJ.SAMP_422; |
| else if (argv[i].equals("440")) |
| subsamp = TJ.SAMP_440; |
| else if (argv[i].equals("420")) |
| subsamp = TJ.SAMP_420; |
| else if (argv[i].equals("411")) |
| subsamp = TJ.SAMP_411; |
| else if (argv[i].equals("441")) |
| subsamp = TJ.SAMP_441; |
| else |
| usage(); |
| } else if (argv[i].equalsIgnoreCase("-componly")) |
| compOnly = true; |
| else if (argv[i].equalsIgnoreCase("-nowrite")) |
| write = false; |
| else if (argv[i].equalsIgnoreCase("-limitscans")) |
| limitScans = true; |
| else if (argv[i].equalsIgnoreCase("-maxmemory") && |
| i < argv.length - 1) { |
| int temp = -1; |
| |
| try { |
| temp = Integer.parseInt(argv[++i]); |
| } catch (NumberFormatException e) {} |
| if (temp < 0) |
| usage(); |
| maxMemory = temp; |
| } else if (argv[i].equalsIgnoreCase("-maxpixels") && |
| i < argv.length - 1) { |
| int temp = -1; |
| |
| try { |
| temp = Integer.parseInt(argv[++i]); |
| } catch (NumberFormatException e) {} |
| if (temp < 0) |
| usage(); |
| maxPixels = temp; |
| } else if (argv[i].equalsIgnoreCase("-restart") && |
| i < argv.length - 1) { |
| int temp = -1; |
| String arg = argv[++i]; |
| Scanner scanner = new Scanner(arg).useDelimiter("b|B"); |
| |
| try { |
| temp = scanner.nextInt(); |
| } catch (Exception e) {} |
| |
| if (temp < 0 || temp > 65535 || scanner.hasNext()) |
| usage(); |
| if (arg.endsWith("B") || arg.endsWith("b")) |
| restartIntervalBlocks = temp; |
| else |
| restartIntervalRows = temp; |
| } else if (argv[i].equalsIgnoreCase("-stoponwarning")) |
| stopOnWarning = true; |
| else usage(); |
| } |
| } |
| |
| if (precision == 16 && !lossless) |
| throw new Exception("-lossless must be specified along with -precision 16"); |
| if (precision != 8 && doYUV) |
| throw new Exception("-yuv requires 8-bit data precision"); |
| if (lossless && doYUV) |
| throw new Exception("ERROR: -lossless and -yuv are incompatible"); |
| |
| if ((sf.getNum() != 1 || sf.getDenom() != 1) && doTile) { |
| System.out.println("Disabling tiled compression/decompression tests, because those tests do not"); |
| System.out.println("work when scaled decompression is enabled.\n"); |
| doTile = false; |
| xformOpt &= (~TJTransform.OPT_CROP); |
| } |
| |
| if (isCropped(cr)) { |
| if (!decompOnly) |
| throw new Exception("ERROR: Partial image decompression can only be enabled for JPEG input images"); |
| if (doTile) { |
| System.out.println("Disabling tiled compression/decompression tests, because those tests do not"); |
| System.out.println("work when partial image decompression is enabled.\n"); |
| doTile = false; |
| xformOpt &= (~TJTransform.OPT_CROP); |
| } |
| if (doYUV) |
| throw new Exception("ERROR: -crop and -yuv are incompatible"); |
| } |
| |
| if (!decompOnly) { |
| int[] width = new int[1], height = new int[1], |
| pixelFormat = new int[1]; |
| |
| tjc = new TJCompressor(); |
| tjc.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0); |
| tjc.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0); |
| tjc.set(TJ.PARAM_MAXPIXELS, maxPixels); |
| |
| pixelFormat[0] = pf; |
| srcBuf = tjc.loadImage(precision, argv[0], width, 1, height, |
| pixelFormat); |
| w = width[0]; h = height[0]; pf = pixelFormat[0]; |
| int index = -1; |
| if ((index = argv[0].lastIndexOf('.')) >= 0) |
| argv[0] = argv[0].substring(0, index); |
| } |
| |
| if (quiet == 1 && !decompOnly) { |
| System.out.println("All performance values in Mpixels/sec\n"); |
| System.out.format("Pixel JPEG JPEG %s %s ", |
| (doTile ? "Tile " : "Image"), |
| (doTile ? "Tile " : "Image")); |
| if (doYUV) |
| System.out.print("Encode "); |
| System.out.print("Comp Comp Decomp "); |
| if (doYUV) |
| System.out.print("Decode"); |
| System.out.print("\n"); |
| System.out.format("Format Format %s Width Height ", |
| lossless ? "PSV " : "Qual"); |
| if (doYUV) |
| System.out.print("Perf "); |
| System.out.print("Perf Ratio Perf "); |
| if (doYUV) |
| System.out.print("Perf"); |
| System.out.println("\n"); |
| } |
| |
| if (decompOnly) { |
| decompTest(argv[0]); |
| System.out.println(""); |
| System.exit(retval); |
| } |
| |
| System.gc(); |
| if (lossless) { |
| if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7) |
| throw new Exception("PSV must be between 1 and 7."); |
| } else { |
| if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100) |
| throw new Exception("Quality must be between 1 and 100."); |
| } |
| if (subsamp >= 0 && subsamp < TJ.NUMSAMP) { |
| for (int i = maxQual; i >= minQual; i--) |
| fullTest(tjc, srcBuf, w, h, subsamp, i, argv[0]); |
| System.out.println(""); |
| } else { |
| if (pf != TJ.PF_CMYK) { |
| for (int i = maxQual; i >= minQual; i--) |
| fullTest(tjc, srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]); |
| System.out.println(""); |
| System.gc(); |
| } |
| for (int i = maxQual; i >= minQual; i--) |
| fullTest(tjc, srcBuf, w, h, TJ.SAMP_420, i, argv[0]); |
| System.out.println(""); |
| System.gc(); |
| for (int i = maxQual; i >= minQual; i--) |
| fullTest(tjc, srcBuf, w, h, TJ.SAMP_422, i, argv[0]); |
| System.out.println(""); |
| System.gc(); |
| for (int i = maxQual; i >= minQual; i--) |
| fullTest(tjc, srcBuf, w, h, TJ.SAMP_444, i, argv[0]); |
| System.out.println(""); |
| } |
| |
| } catch (Exception e) { |
| if (e instanceof TJException) { |
| TJException tje = (TJException)e; |
| |
| System.out.println((tje.getErrorCode() == TJ.ERR_WARNING ? |
| "WARNING: " : "ERROR: ") + tje.getMessage()); |
| } else |
| System.out.println("ERROR: " + e.getMessage()); |
| e.printStackTrace(); |
| retval = -1; |
| } |
| |
| System.exit(retval); |
| } |
| |
| } |