You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
960 lines
33 KiB
960 lines
33 KiB
/* |
|
* Copyright (C)2011-2018 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.*; |
|
|
|
@SuppressWarnings("checkstyle:JavadocType") |
|
final class TJUnitTest { |
|
|
|
private TJUnitTest() {} |
|
|
|
static final String CLASS_NAME = |
|
new TJUnitTest().getClass().getName(); |
|
|
|
static void usage() { |
|
System.out.println("\nUSAGE: java " + CLASS_NAME + " [options]\n"); |
|
System.out.println("Options:"); |
|
System.out.println("-yuv = test YUV encoding/decoding support"); |
|
System.out.println("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest"); |
|
System.out.println(" 4-byte boundary"); |
|
System.out.println("-bi = test BufferedImage support\n"); |
|
System.exit(1); |
|
} |
|
|
|
static final String[] SUBNAME_LONG = { |
|
"4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1" |
|
}; |
|
static final String[] SUBNAME = { |
|
"444", "422", "420", "GRAY", "440", "411" |
|
}; |
|
|
|
static final String[] PIXFORMATSTR = { |
|
"RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale", |
|
"RGBA", "BGRA", "ABGR", "ARGB", "CMYK" |
|
}; |
|
|
|
static final int[] FORMATS_3BYTE = { |
|
TJ.PF_RGB, TJ.PF_BGR |
|
}; |
|
static final int[] FORMATS_3BYTEBI = { |
|
BufferedImage.TYPE_3BYTE_BGR |
|
}; |
|
static final int[] FORMATS_4BYTE = { |
|
TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB, TJ.PF_CMYK |
|
}; |
|
static final int[] FORMATS_4BYTEBI = { |
|
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 |
|
}; |
|
static final int[] FORMATS_GRAY = { |
|
TJ.PF_GRAY |
|
}; |
|
static final int[] FORMATS_GRAYBI = { |
|
BufferedImage.TYPE_BYTE_GRAY |
|
}; |
|
static final int[] FORMATS_RGB = { |
|
TJ.PF_RGB |
|
}; |
|
|
|
private static boolean doYUV = false; |
|
private static int pad = 4; |
|
private static boolean bi = false; |
|
|
|
private static int exitStatus = 0; |
|
|
|
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: |
|
return TJ.PF_RGBX; |
|
case BufferedImage.TYPE_INT_RGB: |
|
return TJ.PF_BGRX; |
|
case BufferedImage.TYPE_INT_ARGB: |
|
case BufferedImage.TYPE_INT_ARGB_PRE: |
|
return TJ.PF_BGRA; |
|
default: |
|
return 0; |
|
} |
|
} |
|
|
|
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"; |
|
default: |
|
return "Unknown"; |
|
} |
|
} |
|
|
|
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 = TJ.getAlphaOffset(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; |
|
} |
|
} |
|
} |
|
|
|
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 = TJ.getAlphaOffset(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); |
|
} |
|
} |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
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 = TJ.getAlphaOffset(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_GRAY) |
|
roffset = goffset = boffset = 0; |
|
|
|
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; |
|
} |
|
|
|
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 = TJ.getAlphaOffset(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; |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
static int pad(int v, int p) { |
|
return ((v + (p) - 1) & (~((p) - 1))); |
|
} |
|
|
|
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; |
|
} |
|
|
|
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(); |
|
} |
|
|
|
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, |
|
SUBNAME_LONG[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 ... ", SUBNAME_LONG[subsamp], |
|
buStrLong, jpegQual); |
|
tjc.setSourceImage(yuvImage); |
|
} else { |
|
System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong, |
|
SUBNAME_LONG[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; |
|
} |
|
|
|
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 ", SUBNAME_LONG[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 ... ", SUBNAME_LONG[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; |
|
} |
|
} |
|
|
|
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]); |
|
} |
|
} |
|
|
|
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(); |
|
} |
|
|
|
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; |
|
else if (argv[i].equalsIgnoreCase("-noyuvpad")) |
|
pad = 1; |
|
else if (argv[i].equalsIgnoreCase("-bi")) { |
|
bi = true; |
|
testName = "javabitest"; |
|
} else |
|
usage(); |
|
} |
|
if (doYUV) |
|
FORMATS_4BYTE[4] = -1; |
|
doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_444, |
|
testName); |
|
doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_444, |
|
testName); |
|
doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_422, |
|
testName); |
|
doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_422, |
|
testName); |
|
doTest(39, 41, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_420, |
|
testName); |
|
doTest(41, 35, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_420, |
|
testName); |
|
doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_440, |
|
testName); |
|
doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_440, |
|
testName); |
|
doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_411, |
|
testName); |
|
doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_411, |
|
testName); |
|
doTest(39, 41, bi ? FORMATS_GRAYBI : FORMATS_GRAY, TJ.SAMP_GRAY, |
|
testName); |
|
doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_GRAY, |
|
testName); |
|
FORMATS_4BYTE[4] = -1; |
|
doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_GRAY, |
|
testName); |
|
if (!bi) |
|
bufSizeTest(); |
|
if (doYUV && !bi) { |
|
System.out.print("\n--------------------\n\n"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_444, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_422, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_420, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_440, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_411, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_RGB, TJ.SAMP_GRAY, "javatest_yuv0"); |
|
doTest(48, 48, FORMATS_GRAY, TJ.SAMP_GRAY, "javatest_yuv0"); |
|
} |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
exitStatus = -1; |
|
} |
|
System.exit(exitStatus); |
|
} |
|
}
|
|
|