| Index: java/TJUnitTest.java
|
| diff --git a/java/TJUnitTest.java b/java/TJUnitTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..444e798530ac1634d8981cdebde989c7c3da1057
|
| --- /dev/null
|
| +++ b/java/TJUnitTest.java
|
| @@ -0,0 +1,970 @@
|
| +/*
|
| + * Copyright (C)2011-2016 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.
|
| + */
|
| +
|
| +/*
|
| + * This program tests the various code paths in the TurboJPEG JNI Wrapper
|
| + */
|
| +
|
| +import java.io.*;
|
| +import java.util.*;
|
| +import java.awt.image.*;
|
| +import javax.imageio.*;
|
| +import java.nio.*;
|
| +import org.libjpegturbo.turbojpeg.*;
|
| +
|
| +public class TJUnitTest {
|
| +
|
| + private static final String classname =
|
| + new TJUnitTest().getClass().getName();
|
| +
|
| + private static void usage() {
|
| + System.out.println("\nUSAGE: java " + classname + " [options]\n");
|
| + System.out.println("Options:\n");
|
| + System.out.println("-yuv = test YUV encoding/decoding support\n");
|
| + System.out.println("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
|
| + System.out.println(" 4-byte boundary\n");
|
| + System.out.println("-bi = test BufferedImage support\n");
|
| + System.exit(1);
|
| + }
|
| +
|
| + private static final String[] subNameLong = {
|
| + "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
|
| + };
|
| + private static final String[] subName = {
|
| + "444", "422", "420", "GRAY", "440", "411"
|
| + };
|
| +
|
| + private static final String[] pixFormatStr = {
|
| + "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
|
| + "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
|
| + };
|
| +
|
| + private static final int[] alphaOffset = {
|
| + -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
|
| + };
|
| +
|
| + private static final int[] _3byteFormats = {
|
| + TJ.PF_RGB, TJ.PF_BGR
|
| + };
|
| + private static final int[] _3byteFormatsBI = {
|
| + BufferedImage.TYPE_3BYTE_BGR
|
| + };
|
| + private static final int[] _4byteFormats = {
|
| + TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB, TJ.PF_CMYK
|
| + };
|
| + private static final int[] _4byteFormatsBI = {
|
| + BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_INT_RGB,
|
| + BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE,
|
| + BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE
|
| + };
|
| + private static final int[] onlyGray = {
|
| + TJ.PF_GRAY
|
| + };
|
| + private static final int[] onlyGrayBI = {
|
| + BufferedImage.TYPE_BYTE_GRAY
|
| + };
|
| + private static final int[] onlyRGB = {
|
| + TJ.PF_RGB
|
| + };
|
| +
|
| + private static boolean doYUV = false;
|
| + private static int pad = 4;
|
| + private static boolean bi = false;
|
| +
|
| + private static int exitStatus = 0;
|
| +
|
| + private static int biTypePF(int biType) {
|
| + ByteOrder byteOrder = ByteOrder.nativeOrder();
|
| + switch(biType) {
|
| + case BufferedImage.TYPE_3BYTE_BGR:
|
| + return TJ.PF_BGR;
|
| + case BufferedImage.TYPE_4BYTE_ABGR:
|
| + case BufferedImage.TYPE_4BYTE_ABGR_PRE:
|
| + return TJ.PF_ABGR;
|
| + case BufferedImage.TYPE_BYTE_GRAY:
|
| + return TJ.PF_GRAY;
|
| + case BufferedImage.TYPE_INT_BGR:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + return TJ.PF_XBGR;
|
| + else
|
| + return TJ.PF_RGBX;
|
| + case BufferedImage.TYPE_INT_RGB:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + return TJ.PF_XRGB;
|
| + else
|
| + return TJ.PF_BGRX;
|
| + case BufferedImage.TYPE_INT_ARGB:
|
| + case BufferedImage.TYPE_INT_ARGB_PRE:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + return TJ.PF_ARGB;
|
| + else
|
| + return TJ.PF_BGRA;
|
| + }
|
| + return 0;
|
| + }
|
| +
|
| + private static String biTypeStr(int biType) {
|
| + switch(biType) {
|
| + case BufferedImage.TYPE_3BYTE_BGR:
|
| + return "3BYTE_BGR";
|
| + case BufferedImage.TYPE_4BYTE_ABGR:
|
| + return "4BYTE_ABGR";
|
| + case BufferedImage.TYPE_4BYTE_ABGR_PRE:
|
| + return "4BYTE_ABGR_PRE";
|
| + case BufferedImage.TYPE_BYTE_GRAY:
|
| + return "BYTE_GRAY";
|
| + case BufferedImage.TYPE_INT_BGR:
|
| + return "INT_BGR";
|
| + case BufferedImage.TYPE_INT_RGB:
|
| + return "INT_RGB";
|
| + case BufferedImage.TYPE_INT_ARGB:
|
| + return "INT_ARGB";
|
| + case BufferedImage.TYPE_INT_ARGB_PRE:
|
| + return "INT_ARGB_PRE";
|
| + }
|
| + return "Unknown";
|
| + }
|
| +
|
| + private static void initBuf(byte[] buf, int w, int pitch, int h, int pf,
|
| + int flags) throws Exception {
|
| + int roffset = TJ.getRedOffset(pf);
|
| + int goffset = TJ.getGreenOffset(pf);
|
| + int boffset = TJ.getBlueOffset(pf);
|
| + int aoffset = alphaOffset[pf];
|
| + int ps = TJ.getPixelSize(pf);
|
| + int index, row, col, halfway = 16;
|
| +
|
| + if (pf == TJ.PF_GRAY) {
|
| + Arrays.fill(buf, (byte)0);
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = pitch * (h - row - 1) + col;
|
| + else
|
| + index = pitch * row + col;
|
| + if (((row / 8) + (col / 8)) % 2 == 0)
|
| + buf[index] = (row < halfway) ? (byte)255 : 0;
|
| + else
|
| + buf[index] = (row < halfway) ? 76 : (byte)226;
|
| + }
|
| + }
|
| + return;
|
| + }
|
| + if (pf == TJ.PF_CMYK) {
|
| + Arrays.fill(buf, (byte)255);
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = (h - row - 1) * w + col;
|
| + else
|
| + index = row * w + col;
|
| + if (((row / 8) + (col / 8)) % 2 == 0) {
|
| + if (row >= halfway) buf[index * ps + 3] = 0;
|
| + } else {
|
| + buf[index * ps + 2] = 0;
|
| + if (row < halfway)
|
| + buf[index * ps + 1] = 0;
|
| + }
|
| + }
|
| + }
|
| + return;
|
| + }
|
| +
|
| + Arrays.fill(buf, (byte)0);
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = pitch * (h - row - 1) + col * ps;
|
| + else
|
| + index = pitch * row + col * ps;
|
| + if (((row / 8) + (col / 8)) % 2 == 0) {
|
| + if (row < halfway) {
|
| + buf[index + roffset] = (byte)255;
|
| + buf[index + goffset] = (byte)255;
|
| + buf[index + boffset] = (byte)255;
|
| + }
|
| + } else {
|
| + buf[index + roffset] = (byte)255;
|
| + if (row >= halfway)
|
| + buf[index + goffset] = (byte)255;
|
| + }
|
| + if (aoffset >= 0)
|
| + buf[index + aoffset] = (byte)255;
|
| + }
|
| + }
|
| + }
|
| +
|
| + private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf,
|
| + int flags) throws Exception {
|
| + int rshift = TJ.getRedOffset(pf) * 8;
|
| + int gshift = TJ.getGreenOffset(pf) * 8;
|
| + int bshift = TJ.getBlueOffset(pf) * 8;
|
| + int ashift = alphaOffset[pf] * 8;
|
| + int index, row, col, halfway = 16;
|
| +
|
| + Arrays.fill(buf, 0);
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = pitch * (h - row - 1) + col;
|
| + else
|
| + index = pitch * row + col;
|
| + if (((row / 8) + (col / 8)) % 2 == 0) {
|
| + if (row < halfway) {
|
| + buf[index] |= (255 << rshift);
|
| + buf[index] |= (255 << gshift);
|
| + buf[index] |= (255 << bshift);
|
| + }
|
| + } else {
|
| + buf[index] |= (255 << rshift);
|
| + if (row >= halfway)
|
| + buf[index] |= (255 << gshift);
|
| + }
|
| + if (ashift >= 0)
|
| + buf[index] |= (255 << ashift);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private static void initImg(BufferedImage img, int pf, int flags)
|
| + throws Exception {
|
| + WritableRaster wr = img.getRaster();
|
| + int imgType = img.getType();
|
| + if (imgType == BufferedImage.TYPE_INT_RGB ||
|
| + imgType == BufferedImage.TYPE_INT_BGR ||
|
| + imgType == BufferedImage.TYPE_INT_ARGB ||
|
| + imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
|
| + SinglePixelPackedSampleModel sm =
|
| + (SinglePixelPackedSampleModel)img.getSampleModel();
|
| + int pitch = sm.getScanlineStride();
|
| + DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
|
| + int[] buf = db.getData();
|
| + initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
|
| + } else {
|
| + ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
|
| + int pitch = sm.getScanlineStride();
|
| + DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
|
| + byte[] buf = db.getData();
|
| + initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
|
| + }
|
| + }
|
| +
|
| + private static void checkVal(int row, int col, int v, String vname, int cv)
|
| + throws Exception {
|
| + v = (v < 0) ? v + 256 : v;
|
| + if (v < cv - 1 || v > cv + 1) {
|
| + throw new Exception("Comp. " + vname + " at " + row + "," + col +
|
| + " should be " + cv + ", not " + v);
|
| + }
|
| + }
|
| +
|
| + private static void checkVal0(int row, int col, int v, String vname)
|
| + throws Exception {
|
| + v = (v < 0) ? v + 256 : v;
|
| + if (v > 1) {
|
| + throw new Exception("Comp. " + vname + " at " + row + "," + col +
|
| + " should be 0, not " + v);
|
| + }
|
| + }
|
| +
|
| + private static void checkVal255(int row, int col, int v, String vname)
|
| + throws Exception {
|
| + v = (v < 0) ? v + 256 : v;
|
| + if (v < 254) {
|
| + throw new Exception("Comp. " + vname + " at " + row + "," + col +
|
| + " should be 255, not " + v);
|
| + }
|
| + }
|
| +
|
| + private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf,
|
| + int subsamp, TJScalingFactor sf, int flags)
|
| + throws Exception {
|
| + int roffset = TJ.getRedOffset(pf);
|
| + int goffset = TJ.getGreenOffset(pf);
|
| + int boffset = TJ.getBlueOffset(pf);
|
| + int aoffset = alphaOffset[pf];
|
| + int ps = TJ.getPixelSize(pf);
|
| + int index, row, col, retval = 1;
|
| + int halfway = 16 * sf.getNum() / sf.getDenom();
|
| + int blockSize = 8 * sf.getNum() / sf.getDenom();
|
| +
|
| + try {
|
| +
|
| + if (pf == TJ.PF_CMYK) {
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = (h - row - 1) * w + col;
|
| + else
|
| + index = row * w + col;
|
| + byte c = buf[index * ps];
|
| + byte m = buf[index * ps + 1];
|
| + byte y = buf[index * ps + 2];
|
| + byte k = buf[index * ps + 3];
|
| + checkVal255(row, col, c, "C");
|
| + if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
|
| + checkVal255(row, col, m, "M");
|
| + checkVal255(row, col, y, "Y");
|
| + if (row < halfway)
|
| + checkVal255(row, col, k, "K");
|
| + else
|
| + checkVal0(row, col, k, "K");
|
| + } else {
|
| + checkVal0(row, col, y, "Y");
|
| + checkVal255(row, col, k, "K");
|
| + if (row < halfway)
|
| + checkVal0(row, col, m, "M");
|
| + else
|
| + checkVal255(row, col, m, "M");
|
| + }
|
| + }
|
| + }
|
| + return 1;
|
| + }
|
| +
|
| + for (row = 0; row < halfway; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = pitch * (h - row - 1) + col * ps;
|
| + else
|
| + index = pitch * row + col * ps;
|
| + byte r = buf[index + roffset];
|
| + byte g = buf[index + goffset];
|
| + byte b = buf[index + boffset];
|
| + byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255;
|
| + if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
|
| + if (row < halfway) {
|
| + checkVal255(row, col, r, "R");
|
| + checkVal255(row, col, g, "G");
|
| + checkVal255(row, col, b, "B");
|
| + } else {
|
| + checkVal0(row, col, r, "R");
|
| + checkVal0(row, col, g, "G");
|
| + checkVal0(row, col, b, "B");
|
| + }
|
| + } else {
|
| + if (subsamp == TJ.SAMP_GRAY) {
|
| + if (row < halfway) {
|
| + checkVal(row, col, r, "R", 76);
|
| + checkVal(row, col, g, "G", 76);
|
| + checkVal(row, col, b, "B", 76);
|
| + } else {
|
| + checkVal(row, col, r, "R", 226);
|
| + checkVal(row, col, g, "G", 226);
|
| + checkVal(row, col, b, "B", 226);
|
| + }
|
| + } else {
|
| + checkVal255(row, col, r, "R");
|
| + if (row < halfway) {
|
| + checkVal0(row, col, g, "G");
|
| + } else {
|
| + checkVal255(row, col, g, "G");
|
| + }
|
| + checkVal0(row, col, b, "B");
|
| + }
|
| + }
|
| + checkVal255(row, col, a, "A");
|
| + }
|
| + }
|
| + } catch(Exception e) {
|
| + System.out.println("\n" + e.getMessage());
|
| + retval = 0;
|
| + }
|
| +
|
| + if (retval == 0) {
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if (pf == TJ.PF_CMYK) {
|
| + int c = buf[pitch * row + col * ps];
|
| + int m = buf[pitch * row + col * ps + 1];
|
| + int y = buf[pitch * row + col * ps + 2];
|
| + int k = buf[pitch * row + col * ps + 3];
|
| + if (c < 0) c += 256;
|
| + if (m < 0) m += 256;
|
| + if (y < 0) y += 256;
|
| + if (k < 0) k += 256;
|
| + System.out.format("%3d/%3d/%3d/%3d ", c, m, y, k);
|
| + } else {
|
| + int r = buf[pitch * row + col * ps + roffset];
|
| + int g = buf[pitch * row + col * ps + goffset];
|
| + int b = buf[pitch * row + col * ps + boffset];
|
| + if (r < 0) r += 256;
|
| + if (g < 0) g += 256;
|
| + if (b < 0) b += 256;
|
| + System.out.format("%3d/%3d/%3d ", r, g, b);
|
| + }
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + }
|
| + return retval;
|
| + }
|
| +
|
| + private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
|
| + int subsamp, TJScalingFactor sf, int flags)
|
| + throws Exception {
|
| + int rshift = TJ.getRedOffset(pf) * 8;
|
| + int gshift = TJ.getGreenOffset(pf) * 8;
|
| + int bshift = TJ.getBlueOffset(pf) * 8;
|
| + int ashift = alphaOffset[pf] * 8;
|
| + int index, row, col, retval = 1;
|
| + int halfway = 16 * sf.getNum() / sf.getDenom();
|
| + int blockSize = 8 * sf.getNum() / sf.getDenom();
|
| +
|
| + try {
|
| + for (row = 0; row < halfway; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + if ((flags & TJ.FLAG_BOTTOMUP) != 0)
|
| + index = pitch * (h - row - 1) + col;
|
| + else
|
| + index = pitch * row + col;
|
| + int r = (buf[index] >> rshift) & 0xFF;
|
| + int g = (buf[index] >> gshift) & 0xFF;
|
| + int b = (buf[index] >> bshift) & 0xFF;
|
| + int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255;
|
| + if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
|
| + if (row < halfway) {
|
| + checkVal255(row, col, r, "R");
|
| + checkVal255(row, col, g, "G");
|
| + checkVal255(row, col, b, "B");
|
| + } else {
|
| + checkVal0(row, col, r, "R");
|
| + checkVal0(row, col, g, "G");
|
| + checkVal0(row, col, b, "B");
|
| + }
|
| + } else {
|
| + if (subsamp == TJ.SAMP_GRAY) {
|
| + if (row < halfway) {
|
| + checkVal(row, col, r, "R", 76);
|
| + checkVal(row, col, g, "G", 76);
|
| + checkVal(row, col, b, "B", 76);
|
| + } else {
|
| + checkVal(row, col, r, "R", 226);
|
| + checkVal(row, col, g, "G", 226);
|
| + checkVal(row, col, b, "B", 226);
|
| + }
|
| + } else {
|
| + checkVal255(row, col, r, "R");
|
| + if (row < halfway) {
|
| + checkVal0(row, col, g, "G");
|
| + } else {
|
| + checkVal255(row, col, g, "G");
|
| + }
|
| + checkVal0(row, col, b, "B");
|
| + }
|
| + }
|
| + checkVal255(row, col, a, "A");
|
| + }
|
| + }
|
| + } catch(Exception e) {
|
| + System.out.println("\n" + e.getMessage());
|
| + retval = 0;
|
| + }
|
| +
|
| + if (retval == 0) {
|
| + for (row = 0; row < h; row++) {
|
| + for (col = 0; col < w; col++) {
|
| + int r = (buf[pitch * row + col] >> rshift) & 0xFF;
|
| + int g = (buf[pitch * row + col] >> gshift) & 0xFF;
|
| + int b = (buf[pitch * row + col] >> bshift) & 0xFF;
|
| + if (r < 0) r += 256;
|
| + if (g < 0) g += 256;
|
| + if (b < 0) b += 256;
|
| + System.out.format("%3d/%3d/%3d ", r, g, b);
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + }
|
| + return retval;
|
| + }
|
| +
|
| + private static int checkImg(BufferedImage img, int pf, int subsamp,
|
| + TJScalingFactor sf, int flags) throws Exception {
|
| + WritableRaster wr = img.getRaster();
|
| + int imgType = img.getType();
|
| + if (imgType == BufferedImage.TYPE_INT_RGB ||
|
| + imgType == BufferedImage.TYPE_INT_BGR ||
|
| + imgType == BufferedImage.TYPE_INT_ARGB ||
|
| + imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
|
| + SinglePixelPackedSampleModel sm =
|
| + (SinglePixelPackedSampleModel)img.getSampleModel();
|
| + int pitch = sm.getScanlineStride();
|
| + DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
|
| + int[] buf = db.getData();
|
| + return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
|
| + subsamp, sf, flags);
|
| + } else {
|
| + ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
|
| + int pitch = sm.getScanlineStride();
|
| + DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
|
| + byte[] buf = db.getData();
|
| + return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
|
| + sf, flags);
|
| + }
|
| + }
|
| +
|
| + private static int PAD(int v, int p) {
|
| + return ((v + (p) - 1) & (~((p) - 1)));
|
| + }
|
| +
|
| + private static int checkBufYUV(byte[] buf, int size, int w, int h,
|
| + int subsamp, TJScalingFactor sf)
|
| + throws Exception {
|
| + int row, col;
|
| + int hsf = TJ.getMCUWidth(subsamp) / 8, vsf = TJ.getMCUHeight(subsamp) / 8;
|
| + int pw = PAD(w, hsf), ph = PAD(h, vsf);
|
| + int cw = pw / hsf, ch = ph / vsf;
|
| + int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad);
|
| + int retval = 1;
|
| + int correctsize = ypitch * ph +
|
| + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
|
| + int halfway = 16 * sf.getNum() / sf.getDenom();
|
| + int blockSize = 8 * sf.getNum() / sf.getDenom();
|
| +
|
| + try {
|
| + if (size != correctsize)
|
| + throw new Exception("Incorrect size " + size + ". Should be " +
|
| + correctsize);
|
| +
|
| + for (row = 0; row < ph; row++) {
|
| + for (col = 0; col < pw; col++) {
|
| + byte y = buf[ypitch * row + col];
|
| + if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
|
| + if (row < halfway)
|
| + checkVal255(row, col, y, "Y");
|
| + else
|
| + checkVal0(row, col, y, "Y");
|
| + } else {
|
| + if (row < halfway)
|
| + checkVal(row, col, y, "Y", 76);
|
| + else
|
| + checkVal(row, col, y, "Y", 226);
|
| + }
|
| + }
|
| + }
|
| + if (subsamp != TJ.SAMP_GRAY) {
|
| + halfway = 16 / vsf * sf.getNum() / sf.getDenom();
|
| + for (row = 0; row < ch; row++) {
|
| + for (col = 0; col < cw; col++) {
|
| + byte u = buf[ypitch * ph + (uvpitch * row + col)],
|
| + v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
|
| + if (((row * vsf / blockSize) + (col * hsf / blockSize)) % 2 == 0) {
|
| + checkVal(row, col, u, "U", 128);
|
| + checkVal(row, col, v, "V", 128);
|
| + } else {
|
| + if (row < halfway) {
|
| + checkVal(row, col, u, "U", 85);
|
| + checkVal255(row, col, v, "V");
|
| + } else {
|
| + checkVal0(row, col, u, "U");
|
| + checkVal(row, col, v, "V", 149);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + } catch(Exception e) {
|
| + System.out.println("\n" + e.getMessage());
|
| + retval = 0;
|
| + }
|
| +
|
| + if (retval == 0) {
|
| + for (row = 0; row < ph; row++) {
|
| + for (col = 0; col < pw; col++) {
|
| + int y = buf[ypitch * row + col];
|
| + if (y < 0) y += 256;
|
| + System.out.format("%3d ", y);
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + System.out.print("\n");
|
| + for (row = 0; row < ch; row++) {
|
| + for (col = 0; col < cw; col++) {
|
| + int u = buf[ypitch * ph + (uvpitch * row + col)];
|
| + if (u < 0) u += 256;
|
| + System.out.format("%3d ", u);
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + System.out.print("\n");
|
| + for (row = 0; row < ch; row++) {
|
| + for (col = 0; col < cw; col++) {
|
| + int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
|
| + if (v < 0) v += 256;
|
| + System.out.format("%3d ", v);
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + }
|
| +
|
| + return retval;
|
| + }
|
| +
|
| + private static void writeJPEG(byte[] jpegBuf, int jpegBufSize,
|
| + String filename) throws Exception {
|
| + File file = new File(filename);
|
| + FileOutputStream fos = new FileOutputStream(file);
|
| + fos.write(jpegBuf, 0, jpegBufSize);
|
| + fos.close();
|
| + }
|
| +
|
| + private static int compTest(TJCompressor tjc, byte[] dstBuf, int w,
|
| + int h, int pf, String baseName, int subsamp,
|
| + int jpegQual, int flags) throws Exception {
|
| + String tempStr;
|
| + byte[] srcBuf = null;
|
| + BufferedImage img = null;
|
| + String pfStr, pfStrLong;
|
| + String buStr = (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD";
|
| + String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
|
| + "Bottom-Up" : "Top-Down ";
|
| + int size = 0, ps, imgType = pf;
|
| +
|
| + if (bi) {
|
| + pf = biTypePF(imgType);
|
| + pfStr = biTypeStr(imgType);
|
| + pfStrLong = pfStr + " (" + pixFormatStr[pf] + ")";
|
| + } else {
|
| + pfStr = pixFormatStr[pf];
|
| + pfStrLong = pfStr;
|
| + }
|
| + ps = TJ.getPixelSize(pf);
|
| +
|
| + if (bi) {
|
| + img = new BufferedImage(w, h, imgType);
|
| + initImg(img, pf, flags);
|
| + tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
|
| + subName[subsamp] + "_Q" + jpegQual + ".png";
|
| + File file = new File(tempStr);
|
| + ImageIO.write(img, "png", file);
|
| + tjc.setSourceImage(img, 0, 0, 0, 0);
|
| + } else {
|
| + srcBuf = new byte[w * h * ps + 1];
|
| + initBuf(srcBuf, w, w * ps, h, pf, flags);
|
| + tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, pf);
|
| + }
|
| + Arrays.fill(dstBuf, (byte)0);
|
| +
|
| + tjc.setSubsamp(subsamp);
|
| + tjc.setJPEGQuality(jpegQual);
|
| + if (doYUV) {
|
| + System.out.format("%s %s -> YUV %s ... ", pfStrLong, buStrLong,
|
| + subNameLong[subsamp]);
|
| + YUVImage yuvImage = tjc.encodeYUV(pad, flags);
|
| + if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), w, h, subsamp,
|
| + new TJScalingFactor(1, 1)) == 1)
|
| + System.out.print("Passed.\n");
|
| + else {
|
| + System.out.print("FAILED!\n");
|
| + exitStatus = -1;
|
| + }
|
| +
|
| + System.out.format("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp],
|
| + buStrLong, jpegQual);
|
| + tjc.setSourceImage(yuvImage);
|
| + } else {
|
| + System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong,
|
| + subNameLong[subsamp], jpegQual);
|
| + }
|
| + tjc.compress(dstBuf, flags);
|
| + size = tjc.getCompressedSize();
|
| +
|
| + tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
|
| + subName[subsamp] + "_Q" + jpegQual + ".jpg";
|
| + writeJPEG(dstBuf, size, tempStr);
|
| + System.out.println("Done.\n Result in " + tempStr);
|
| +
|
| + return size;
|
| + }
|
| +
|
| + private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
|
| + int jpegSize, int w, int h, int pf,
|
| + String baseName, int subsamp, int flags,
|
| + TJScalingFactor sf) throws Exception {
|
| + String pfStr, pfStrLong, tempStr;
|
| + String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
|
| + "Bottom-Up" : "Top-Down ";
|
| + int scaledWidth = sf.getScaled(w);
|
| + int scaledHeight = sf.getScaled(h);
|
| + int temp1, temp2, imgType = pf;
|
| + BufferedImage img = null;
|
| + byte[] dstBuf = null;
|
| +
|
| + if (bi) {
|
| + pf = biTypePF(imgType);
|
| + pfStr = biTypeStr(imgType);
|
| + pfStrLong = pfStr + " (" + pixFormatStr[pf] + ")";
|
| + } else {
|
| + pfStr = pixFormatStr[pf];
|
| + pfStrLong = pfStr;
|
| + }
|
| +
|
| + tjd.setSourceImage(jpegBuf, jpegSize);
|
| + if (tjd.getWidth() != w || tjd.getHeight() != h ||
|
| + tjd.getSubsamp() != subsamp)
|
| + throw new Exception("Incorrect JPEG header");
|
| +
|
| + temp1 = scaledWidth;
|
| + temp2 = scaledHeight;
|
| + temp1 = tjd.getScaledWidth(temp1, temp2);
|
| + temp2 = tjd.getScaledHeight(temp1, temp2);
|
| + if (temp1 != scaledWidth || temp2 != scaledHeight)
|
| + throw new Exception("Scaled size mismatch");
|
| +
|
| + if (doYUV) {
|
| + System.out.format("JPEG -> YUV %s ", subNameLong[subsamp]);
|
| + if(!sf.isOne())
|
| + System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom());
|
| + else System.out.print("... ");
|
| + YUVImage yuvImage = tjd.decompressToYUV(scaledWidth, pad, scaledHeight,
|
| + flags);
|
| + if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), scaledWidth,
|
| + scaledHeight, subsamp, sf) == 1)
|
| + System.out.print("Passed.\n");
|
| + else {
|
| + System.out.print("FAILED!\n"); exitStatus = -1;
|
| + }
|
| +
|
| + System.out.format("YUV %s -> %s %s ... ", subNameLong[subsamp],
|
| + pfStrLong, buStrLong);
|
| + tjd.setSourceImage(yuvImage);
|
| + } else {
|
| + System.out.format("JPEG -> %s %s ", pfStrLong, buStrLong);
|
| + if(!sf.isOne())
|
| + System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom());
|
| + else System.out.print("... ");
|
| + }
|
| + if (bi)
|
| + img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags);
|
| + else
|
| + dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
|
| +
|
| + if (bi) {
|
| + tempStr = baseName + "_dec_" + pfStr + "_" +
|
| + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" +
|
| + subName[subsamp] + "_" +
|
| + (double)sf.getNum() / (double)sf.getDenom() + "x" + ".png";
|
| + File file = new File(tempStr);
|
| + ImageIO.write(img, "png", file);
|
| + }
|
| +
|
| + if ((bi && checkImg(img, pf, subsamp, sf, flags) == 1) ||
|
| + (!bi && checkBuf(dstBuf, scaledWidth,
|
| + scaledWidth * TJ.getPixelSize(pf), scaledHeight, pf,
|
| + subsamp, sf, flags) == 1))
|
| + System.out.print("Passed.\n");
|
| + else {
|
| + System.out.print("FAILED!\n");
|
| + exitStatus = -1;
|
| + }
|
| + }
|
| +
|
| + private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
|
| + int jpegSize, int w, int h, int pf,
|
| + String baseName, int subsamp,
|
| + int flags) throws Exception {
|
| + int i;
|
| + TJScalingFactor[] sf = TJ.getScalingFactors();
|
| + for (i = 0; i < sf.length; i++) {
|
| + int num = sf[i].getNum();
|
| + int denom = sf[i].getDenom();
|
| + if (subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY ||
|
| + (subsamp == TJ.SAMP_411 && num == 1 &&
|
| + (denom == 2 || denom == 1)) ||
|
| + (subsamp != TJ.SAMP_411 && num == 1 &&
|
| + (denom == 4 || denom == 2 || denom == 1)))
|
| + decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
|
| + flags, sf[i]);
|
| + }
|
| + }
|
| +
|
| + private static void doTest(int w, int h, int[] formats, int subsamp,
|
| + String baseName) throws Exception {
|
| + TJCompressor tjc = null;
|
| + TJDecompressor tjd = null;
|
| + int size;
|
| + byte[] dstBuf;
|
| +
|
| + dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
|
| +
|
| + try {
|
| + tjc = new TJCompressor();
|
| + tjd = new TJDecompressor();
|
| +
|
| + for (int pf : formats) {
|
| + if (pf < 0) continue;
|
| + for (int i = 0; i < 2; i++) {
|
| + int flags = 0;
|
| + if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 ||
|
| + subsamp == TJ.SAMP_440 || subsamp == TJ.SAMP_411)
|
| + flags |= TJ.FLAG_FASTUPSAMPLE;
|
| + if (i == 1)
|
| + flags |= TJ.FLAG_BOTTOMUP;
|
| + size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100,
|
| + flags);
|
| + decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags);
|
| + if (pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi) {
|
| + System.out.print("\n");
|
| + decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX),
|
| + baseName, subsamp, flags);
|
| + }
|
| + System.out.print("\n");
|
| + }
|
| + }
|
| + System.out.print("--------------------\n\n");
|
| + } catch(Exception e) {
|
| + if (tjc != null) tjc.close();
|
| + if (tjd != null) tjd.close();
|
| + throw e;
|
| + }
|
| + if (tjc != null) tjc.close();
|
| + if (tjd != null) tjd.close();
|
| + }
|
| +
|
| + private static void bufSizeTest() throws Exception {
|
| + int w, h, i, subsamp;
|
| + byte[] srcBuf, dstBuf = null;
|
| + YUVImage dstImage = null;
|
| + TJCompressor tjc = null;
|
| + Random r = new Random();
|
| +
|
| + try {
|
| + tjc = new TJCompressor();
|
| + System.out.println("Buffer size regression test");
|
| + for (subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) {
|
| + for (w = 1; w < 48; w++) {
|
| + int maxh = (w == 1) ? 2048 : 48;
|
| + for (h = 1; h < maxh; h++) {
|
| + if (h % 100 == 0)
|
| + System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
|
| + srcBuf = new byte[w * h * 4];
|
| + if (doYUV)
|
| + dstImage = new YUVImage(w, pad, h, subsamp);
|
| + else
|
| + dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
|
| + for (i = 0; i < w * h * 4; i++) {
|
| + srcBuf[i] = (byte)(r.nextInt(2) * 255);
|
| + }
|
| + tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, TJ.PF_BGRX);
|
| + tjc.setSubsamp(subsamp);
|
| + tjc.setJPEGQuality(100);
|
| + if (doYUV)
|
| + tjc.encodeYUV(dstImage, 0);
|
| + else
|
| + tjc.compress(dstBuf, 0);
|
| +
|
| + srcBuf = new byte[h * w * 4];
|
| + if (doYUV)
|
| + dstImage = new YUVImage(h, pad, w, subsamp);
|
| + else
|
| + dstBuf = new byte[TJ.bufSize(h, w, subsamp)];
|
| + for (i = 0; i < h * w * 4; i++) {
|
| + srcBuf[i] = (byte)(r.nextInt(2) * 255);
|
| + }
|
| + tjc.setSourceImage(srcBuf, 0, 0, h, 0, w, TJ.PF_BGRX);
|
| + if (doYUV)
|
| + tjc.encodeYUV(dstImage, 0);
|
| + else
|
| + tjc.compress(dstBuf, 0);
|
| + }
|
| + dstImage = null;
|
| + dstBuf = null;
|
| + System.gc();
|
| + }
|
| + }
|
| + System.out.println("Done. ");
|
| + } catch(Exception e) {
|
| + if (tjc != null) tjc.close();
|
| + throw e;
|
| + }
|
| + if (tjc != null) tjc.close();
|
| + }
|
| +
|
| + public static void main(String[] argv) {
|
| + try {
|
| + String testName = "javatest";
|
| + for (int i = 0; i < argv.length; i++) {
|
| + if (argv[i].equalsIgnoreCase("-yuv"))
|
| + doYUV = true;
|
| + if (argv[i].equalsIgnoreCase("-noyuvpad"))
|
| + pad = 1;
|
| + if (argv[i].substring(0, 1).equalsIgnoreCase("-h") ||
|
| + argv[i].equalsIgnoreCase("-?"))
|
| + usage();
|
| + if (argv[i].equalsIgnoreCase("-bi")) {
|
| + bi = true;
|
| + testName = "javabitest";
|
| + }
|
| + }
|
| + if (doYUV)
|
| + _4byteFormats[4] = -1;
|
| + doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444,
|
| + testName);
|
| + doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444,
|
| + testName);
|
| + doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422,
|
| + testName);
|
| + doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422,
|
| + testName);
|
| + doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420,
|
| + testName);
|
| + doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420,
|
| + testName);
|
| + doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440,
|
| + testName);
|
| + doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440,
|
| + testName);
|
| + doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_411,
|
| + testName);
|
| + doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_411,
|
| + testName);
|
| + doTest(39, 41, bi ? onlyGrayBI : onlyGray, TJ.SAMP_GRAY, testName);
|
| + doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY,
|
| + testName);
|
| + _4byteFormats[4] = -1;
|
| + doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
|
| + testName);
|
| + if (!bi)
|
| + bufSizeTest();
|
| + if (doYUV && !bi) {
|
| + System.out.print("\n--------------------\n\n");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_422, "javatest_yuv0");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_420, "javatest_yuv0");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_440, "javatest_yuv0");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_411, "javatest_yuv0");
|
| + doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv0");
|
| + doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "javatest_yuv0");
|
| + }
|
| + } catch(Exception e) {
|
| + e.printStackTrace();
|
| + exitStatus = -1;
|
| + }
|
| + System.exit(exitStatus);
|
| + }
|
| +}
|
|
|