2 * Copyright (C)2011-2012 D. R. Commander. All Rights Reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * - Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * - Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * - Neither the name of the libjpeg-turbo Project nor the names of its
13 * contributors may be used to endorse or promote products derived from this
14 * software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
30 * This program tests the various code paths in the TurboJPEG JNI Wrapper
35 import java.awt.image.*;
36 import javax.imageio.*;
38 import org.libjpegturbo.turbojpeg.*;
40 public class TJUnitTest {
42 private static final String classname =
43 new TJUnitTest().getClass().getName();
45 private static void usage() {
46 System.out.println("\nUSAGE: java " + classname + " [options]\n");
47 System.out.println("Options:\n");
48 System.out.println("-yuv = test YUV encoding/decoding support\n");
49 System.out.println("-bi = test BufferedImage support\n");
53 private final static String subNameLong[] = {
54 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0"
56 private final static String subName[] = {
57 "444", "422", "420", "GRAY", "440"
60 private final static String pixFormatStr[] = {
61 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
62 "RGBA", "BGRA", "ABGR", "ARGB"
65 private final static int alphaOffset[] = {
66 -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0
69 private final static int _3byteFormats[] = {
72 private final static int _3byteFormatsBI[] = {
73 BufferedImage.TYPE_3BYTE_BGR
75 private final static int _4byteFormats[] = {
76 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB
78 private final static int _4byteFormatsBI[] = {
79 BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_INT_RGB,
80 BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE,
81 BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE
83 private final static int onlyGray[] = {
86 private final static int onlyGrayBI[] = {
87 BufferedImage.TYPE_BYTE_GRAY
89 private final static int onlyRGB[] = {
93 private final static int YUVENCODE = 1;
94 private final static int YUVDECODE = 2;
95 private static int yuv = 0;
96 private static boolean bi = false;
98 private static int exitStatus = 0;
100 private static int biTypePF(int biType) {
101 ByteOrder byteOrder = ByteOrder.nativeOrder();
103 case BufferedImage.TYPE_3BYTE_BGR:
105 case BufferedImage.TYPE_4BYTE_ABGR:
106 case BufferedImage.TYPE_4BYTE_ABGR_PRE:
108 case BufferedImage.TYPE_BYTE_GRAY:
110 case BufferedImage.TYPE_INT_BGR:
111 if(byteOrder == ByteOrder.BIG_ENDIAN)
115 case BufferedImage.TYPE_INT_RGB:
116 if(byteOrder == ByteOrder.BIG_ENDIAN)
120 case BufferedImage.TYPE_INT_ARGB:
121 case BufferedImage.TYPE_INT_ARGB_PRE:
122 if(byteOrder == ByteOrder.BIG_ENDIAN)
130 private static String biTypeStr(int biType) {
132 case BufferedImage.TYPE_3BYTE_BGR:
134 case BufferedImage.TYPE_4BYTE_ABGR:
136 case BufferedImage.TYPE_4BYTE_ABGR_PRE:
137 return "4BYTE_ABGR_PRE";
138 case BufferedImage.TYPE_BYTE_GRAY:
140 case BufferedImage.TYPE_INT_BGR:
142 case BufferedImage.TYPE_INT_RGB:
144 case BufferedImage.TYPE_INT_ARGB:
146 case BufferedImage.TYPE_INT_ARGB_PRE:
147 return "INT_ARGB_PRE";
153 private static double getTime() {
154 return (double)System.nanoTime() / 1.0e9;
157 private static void initBuf(byte[] buf, int w, int pitch, int h, int pf,
158 int flags) throws Exception {
159 int roffset = TJ.getRedOffset(pf);
160 int goffset = TJ.getGreenOffset(pf);
161 int boffset = TJ.getBlueOffset(pf);
162 int aoffset = alphaOffset[pf];
163 int ps = TJ.getPixelSize(pf);
164 int index, row, col, halfway = 16;
166 Arrays.fill(buf, (byte)0);
167 if(pf == TJ.PF_GRAY) {
168 for(row = 0; row < h; row++) {
169 for(col = 0; col < w; col++) {
170 if((flags & TJ.FLAG_BOTTOMUP) != 0)
171 index = pitch * (h - row - 1) + col;
172 else index = pitch * row + col;
173 if(((row / 8) + (col / 8)) % 2 == 0)
174 buf[index] = (row < halfway) ? (byte)255 : 0;
175 else buf[index] = (row < halfway) ? 76 : (byte)226;
180 for(row = 0; row < h; row++) {
181 for(col = 0; col < w; col++) {
182 if((flags & TJ.FLAG_BOTTOMUP) != 0)
183 index = pitch * (h - row - 1) + col * ps;
184 else index = pitch * row + col * ps;
185 if(((row / 8) + (col / 8)) % 2 == 0) {
187 buf[index + roffset] = (byte)255;
188 buf[index + goffset] = (byte)255;
189 buf[index + boffset] = (byte)255;
193 buf[index + roffset] = (byte)255;
194 if(row >= halfway) buf[index + goffset] = (byte)255;
196 if (aoffset >= 0) buf[index + aoffset] = (byte)255;
201 private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf,
202 int flags) throws Exception {
203 int rshift = TJ.getRedOffset(pf) * 8;
204 int gshift = TJ.getGreenOffset(pf) * 8;
205 int bshift = TJ.getBlueOffset(pf) * 8;
206 int ashift = alphaOffset[pf] * 8;
207 int index, row, col, halfway = 16;
210 for(row = 0; row < h; row++) {
211 for(col = 0; col < w; col++) {
212 if((flags & TJ.FLAG_BOTTOMUP) != 0)
213 index = pitch * (h - row - 1) + col;
214 else index = pitch * row + col;
215 if(((row / 8) + (col / 8)) % 2 == 0) {
217 buf[index] |= (255 << rshift);
218 buf[index] |= (255 << gshift);
219 buf[index] |= (255 << bshift);
223 buf[index] |= (255 << rshift);
224 if(row >= halfway) buf[index] |= (255 << gshift);
226 if (ashift >= 0) buf[index] |= (255 << ashift);
231 private static void initImg(BufferedImage img, int pf, int flags)
233 WritableRaster wr = img.getRaster();
234 int imgType = img.getType();
235 if(imgType == BufferedImage.TYPE_INT_RGB
236 || imgType == BufferedImage.TYPE_INT_BGR
237 || imgType == BufferedImage.TYPE_INT_ARGB
238 || imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
239 SinglePixelPackedSampleModel sm =
240 (SinglePixelPackedSampleModel)img.getSampleModel();
241 int pitch = sm.getScanlineStride();
242 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
243 int[] buf = db.getData();
244 initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
247 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
248 int pitch = sm.getScanlineStride();
249 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
250 byte[] buf = db.getData();
251 initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
255 private static void checkVal(int row, int col, int v, String vname, int cv)
257 v = (v < 0) ? v + 256 : v;
258 if(v < cv - 1 || v > cv + 1) {
259 throw new Exception("\nComp. " + vname + " at " + row + "," + col
260 + " should be " + cv + ", not " + v + "\n");
264 private static void checkVal0(int row, int col, int v, String vname)
266 v = (v < 0) ? v + 256 : v;
268 throw new Exception("\nComp. " + vname + " at " + row + "," + col
269 + " should be 0, not " + v + "\n");
273 private static void checkVal255(int row, int col, int v, String vname)
275 v = (v < 0) ? v + 256 : v;
277 throw new Exception("\nComp. " + vname + " at " + row + "," + col
278 + " should be 255, not " + v + "\n");
282 private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf,
283 int subsamp, TJScalingFactor sf, int flags) throws Exception {
284 int roffset = TJ.getRedOffset(pf);
285 int goffset = TJ.getGreenOffset(pf);
286 int boffset = TJ.getBlueOffset(pf);
287 int aoffset = alphaOffset[pf];
288 int ps = TJ.getPixelSize(pf);
289 int index, row, col, retval = 1;
290 int halfway = 16 * sf.getNum() / sf.getDenom();
291 int blockSize = 8 * sf.getNum() / sf.getDenom();
294 for(row = 0; row < halfway; row++) {
295 for(col = 0; col < w; col++) {
296 if((flags & TJ.FLAG_BOTTOMUP) != 0)
297 index = pitch * (h - row - 1) + col * ps;
298 else index = pitch * row + col * ps;
299 byte r = buf[index + roffset];
300 byte g = buf[index + goffset];
301 byte b = buf[index + boffset];
302 byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255;
303 if(((row / blockSize) + (col / blockSize)) % 2 == 0) {
305 checkVal255(row, col, r, "R");
306 checkVal255(row, col, g, "G");
307 checkVal255(row, col, b, "B");
310 checkVal0(row, col, r, "R");
311 checkVal0(row, col, g, "G");
312 checkVal0(row, col, b, "B");
316 if(subsamp == TJ.SAMP_GRAY) {
318 checkVal(row, col, r, "R", 76);
319 checkVal(row, col, g, "G", 76);
320 checkVal(row, col, b, "B", 76);
323 checkVal(row, col, r, "R", 226);
324 checkVal(row, col, g, "G", 226);
325 checkVal(row, col, b, "B", 226);
329 checkVal255(row, col, r, "R");
331 checkVal0(row, col, g, "G");
334 checkVal255(row, col, g, "G");
336 checkVal0(row, col, b, "B");
339 checkVal255(row, col, a, "A");
344 System.out.println(e);
349 System.out.print("\n");
350 for(row = 0; row < h; row++) {
351 for(col = 0; col < w; col++) {
352 int r = buf[pitch * row + col * ps + roffset];
353 int g = buf[pitch * row + col * ps + goffset];
354 int b = buf[pitch * row + col * ps + boffset];
355 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256;
356 System.out.format("%3d/%3d/%3d ", r, g, b);
358 System.out.print("\n");
364 private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
365 int subsamp, TJScalingFactor sf, int flags) throws Exception {
366 int rshift = TJ.getRedOffset(pf) * 8;
367 int gshift = TJ.getGreenOffset(pf) * 8;
368 int bshift = TJ.getBlueOffset(pf) * 8;
369 int ashift = alphaOffset[pf] * 8;
370 int index, row, col, retval = 1;
371 int halfway = 16 * sf.getNum() / sf.getDenom();
372 int blockSize = 8 * sf.getNum() / sf.getDenom();
375 for(row = 0; row < halfway; row++) {
376 for(col = 0; col < w; col++) {
377 if((flags & TJ.FLAG_BOTTOMUP) != 0)
378 index = pitch * (h - row - 1) + col;
379 else index = pitch * row + col;
380 int r = (buf[index] >> rshift) & 0xFF;
381 int g = (buf[index] >> gshift) & 0xFF;
382 int b = (buf[index] >> bshift) & 0xFF;
383 int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255;
384 if(((row / blockSize) + (col / blockSize)) % 2 == 0) {
386 checkVal255(row, col, r, "R");
387 checkVal255(row, col, g, "G");
388 checkVal255(row, col, b, "B");
391 checkVal0(row, col, r, "R");
392 checkVal0(row, col, g, "G");
393 checkVal0(row, col, b, "B");
397 if(subsamp == TJ.SAMP_GRAY) {
399 checkVal(row, col, r, "R", 76);
400 checkVal(row, col, g, "G", 76);
401 checkVal(row, col, b, "B", 76);
404 checkVal(row, col, r, "R", 226);
405 checkVal(row, col, g, "G", 226);
406 checkVal(row, col, b, "B", 226);
410 checkVal255(row, col, r, "R");
412 checkVal0(row, col, g, "G");
415 checkVal255(row, col, g, "G");
417 checkVal0(row, col, b, "B");
420 checkVal255(row, col, a, "A");
425 System.out.println(e);
430 System.out.print("\n");
431 for(row = 0; row < h; row++) {
432 for(col = 0; col < w; col++) {
433 int r = (buf[pitch * row + col] >> rshift) & 0xFF;
434 int g = (buf[pitch * row + col] >> gshift) & 0xFF;
435 int b = (buf[pitch * row + col] >> bshift) & 0xFF;
436 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256;
437 System.out.format("%3d/%3d/%3d ", r, g, b);
439 System.out.print("\n");
445 private static int checkImg(BufferedImage img, int pf,
446 int subsamp, TJScalingFactor sf, int flags) throws Exception {
447 WritableRaster wr = img.getRaster();
448 int imgType = img.getType();
449 if(imgType == BufferedImage.TYPE_INT_RGB
450 || imgType == BufferedImage.TYPE_INT_BGR
451 || imgType == BufferedImage.TYPE_INT_ARGB
452 || imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
453 SinglePixelPackedSampleModel sm =
454 (SinglePixelPackedSampleModel)img.getSampleModel();
455 int pitch = sm.getScanlineStride();
456 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
457 int[] buf = db.getData();
458 return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
462 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
463 int pitch = sm.getScanlineStride();
464 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
465 byte[] buf = db.getData();
466 return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
471 private static int PAD(int v, int p) {
472 return ((v + (p) - 1) & (~((p) - 1)));
475 private static int checkBufYUV(byte[] buf, int size, int w, int h,
476 int subsamp) throws Exception {
478 int hsf = TJ.getMCUWidth(subsamp)/8, vsf = TJ.getMCUHeight(subsamp)/8;
479 int pw = PAD(w, hsf), ph = PAD(h, vsf);
480 int cw = pw / hsf, ch = ph / vsf;
481 int ypitch = PAD(pw, 4), uvpitch = PAD(cw, 4);
483 int correctsize = ypitch * ph
484 + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
488 if(size != correctsize)
489 throw new Exception("\nIncorrect size " + size + ". Should be "
492 for(row = 0; row < ph; row++) {
493 for(col = 0; col < pw; col++) {
494 byte y = buf[ypitch * row + col];
495 if(((row / 8) + (col / 8)) % 2 == 0) {
496 if(row < halfway) checkVal255(row, col, y, "Y");
497 else checkVal0(row, col, y, "Y");
500 if(row < halfway) checkVal(row, col, y, "Y", 76);
501 else checkVal(row, col, y, "Y", 226);
505 if(subsamp != TJ.SAMP_GRAY) {
507 for(row = 0; row < ch; row++) {
508 for(col = 0; col < cw; col++) {
509 byte u = buf[ypitch * ph + (uvpitch * row + col)],
510 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
511 if(((row * vsf / 8) + (col * hsf / 8)) % 2 == 0) {
512 checkVal(row, col, u, "U", 128);
513 checkVal(row, col, v, "V", 128);
517 checkVal(row, col, u, "U", 85);
518 checkVal255(row, col, v, "V");
521 checkVal0(row, col, u, "U");
522 checkVal(row, col, v, "V", 149);
530 System.out.println(e);
535 for(row = 0; row < ph; row++) {
536 for(col = 0; col < pw; col++) {
537 int y = buf[ypitch * row + col];
539 System.out.format("%3d ", y);
541 System.out.print("\n");
543 System.out.print("\n");
544 for(row = 0; row < ch; row++) {
545 for(col = 0; col < cw; col++) {
546 int u = buf[ypitch * ph + (uvpitch * row + col)];
548 System.out.format("%3d ", u);
550 System.out.print("\n");
552 System.out.print("\n");
553 for(row = 0; row < ch; row++) {
554 for(col = 0; col < cw; col++) {
555 int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
557 System.out.format("%3d ", v);
559 System.out.print("\n");
561 System.out.print("\n");
567 private static void writeJPEG(byte[] jpegBuf, int jpegBufSize,
568 String filename) throws Exception {
569 File file = new File(filename);
570 FileOutputStream fos = new FileOutputStream(file);
571 fos.write(jpegBuf, 0, jpegBufSize);
575 private static int compTest(TJCompressor tjc, byte[] dstBuf, int w,
576 int h, int pf, String baseName, int subsamp, int jpegQual,
577 int flags) throws Exception {
579 byte[] srcBuf = null;
580 BufferedImage img = null;
583 int size = 0, ps, imgType = pf;
586 pf = biTypePF(imgType);
587 pfStr = biTypeStr(imgType);
589 else pfStr = pixFormatStr[pf];
590 ps = TJ.getPixelSize(pf);
592 System.out.print(pfStr + " ");
593 if(bi) System.out.print("(" + pixFormatStr[pf] + ") ");
594 if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up");
595 else System.out.print("Top-Down ");
596 System.out.print(" -> " + subNameLong[subsamp] + " ");
597 if(yuv == YUVENCODE) System.out.print("YUV ... ");
598 else System.out.print("Q" + jpegQual + " ... ");
601 img = new BufferedImage(w, h, imgType);
602 initImg(img, pf, flags);
603 tempstr = baseName + "_enc_" + pfStr + "_"
604 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
605 + subName[subsamp] + "_Q" + jpegQual + ".png";
606 File file = new File(tempstr);
607 ImageIO.write(img, "png", file);
610 srcBuf = new byte[w * h * ps + 1];
611 initBuf(srcBuf, w, w * ps, h, pf, flags);
613 Arrays.fill(dstBuf, (byte)0);
616 tjc.setSubsamp(subsamp);
617 tjc.setJPEGQuality(jpegQual);
619 if(yuv == YUVENCODE) tjc.encodeYUV(img, dstBuf, flags);
620 else tjc.compress(img, dstBuf, flags);
623 tjc.setSourceImage(srcBuf, w, 0, h, pf);
624 if(yuv == YUVENCODE) tjc.encodeYUV(dstBuf, flags);
625 else tjc.compress(dstBuf, flags);
627 size = tjc.getCompressedSize();
631 tempstr = baseName + "_enc_" + pfStr + "_"
632 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
633 + subName[subsamp] + ".yuv";
635 tempstr = baseName + "_enc_" + pfStr + "_"
636 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
637 + subName[subsamp] + "_Q" + jpegQual + ".jpg";
638 writeJPEG(dstBuf, size, tempstr);
640 if(yuv == YUVENCODE) {
641 if(checkBufYUV(dstBuf, size, w, h, subsamp) == 1)
642 System.out.print("Passed.");
644 System.out.print("FAILED!"); exitStatus = -1;
647 else System.out.print("Done.");
648 System.out.format(" %.6f ms\n", t * 1000.);
649 System.out.println(" Result in " + tempstr);
654 private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
655 int jpegSize, int w, int h, int pf, String baseName, int subsamp,
656 int flags, TJScalingFactor sf) throws Exception {
657 String pfStr, tempstr;
659 int scaledWidth = sf.getScaled(w);
660 int scaledHeight = sf.getScaled(h);
661 int temp1, temp2, imgType = pf;
662 BufferedImage img = null;
663 byte[] dstBuf = null;
665 if(yuv == YUVENCODE) return;
668 pf = biTypePF(imgType);
669 pfStr = biTypeStr(imgType);
671 else pfStr = pixFormatStr[pf];
673 System.out.print("JPEG -> ");
675 System.out.print("YUV " + subName[subsamp] + " ... ");
677 System.out.print(pfStr + " ");
678 if(bi) System.out.print("(" + pixFormatStr[pf] + ") ");
679 if((flags & TJ.FLAG_BOTTOMUP) != 0) System.out.print("Bottom-Up ");
680 else System.out.print("Top-Down ");
682 System.out.print(sf.getNum() + "/" + sf.getDenom() + " ... ");
683 else System.out.print("... ");
687 tjd.setJPEGImage(jpegBuf, jpegSize);
688 if(tjd.getWidth() != w || tjd.getHeight() != h
689 || tjd.getSubsamp() != subsamp)
690 throw new Exception("Incorrect JPEG header");
693 temp2 = scaledHeight;
694 temp1 = tjd.getScaledWidth(temp1, temp2);
695 temp2 = tjd.getScaledHeight(temp1, temp2);
696 if(temp1 != scaledWidth || temp2 != scaledHeight)
697 throw new Exception("Scaled size mismatch");
699 if(yuv == YUVDECODE) dstBuf = tjd.decompressToYUV(flags);
702 img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags);
703 else dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
708 tempstr = baseName + "_dec_" + pfStr + "_"
709 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_"
710 + subName[subsamp] + "_" + (double)sf.getNum() / (double)sf.getDenom()
712 File file = new File(tempstr);
713 ImageIO.write(img, "png", file);
716 if(yuv == YUVDECODE) {
717 if(checkBufYUV(dstBuf, dstBuf.length, w, h, subsamp) == 1)
718 System.out.print("Passed.");
720 System.out.print("FAILED!"); exitStatus = -1;
724 if((bi && checkImg(img, pf, subsamp, sf, flags) == 1)
725 || (!bi && checkBuf(dstBuf, scaledWidth, scaledWidth
726 * TJ.getPixelSize(pf), scaledHeight, pf, subsamp, sf, flags) == 1))
727 System.out.print("Passed.");
729 System.out.print("FAILED!"); exitStatus = -1;
732 System.out.format(" %.6f ms\n", t * 1000.);
735 private static void decompTest(TJDecompressor tjd, byte[] jpegBuf,
736 int jpegSize, int w, int h, int pf, String baseName, int subsamp,
737 int flags) throws Exception {
739 if((subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY) && yuv == 0) {
740 TJScalingFactor sf[] = TJ.getScalingFactors();
741 for(i = 0; i < sf.length; i++)
742 decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
746 decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
747 flags, new TJScalingFactor(1, 1));
748 System.out.print("\n");
751 private static void doTest(int w, int h, int[] formats, int subsamp,
752 String baseName) throws Exception {
753 TJCompressor tjc = null;
754 TJDecompressor tjd = null;
758 if(yuv == YUVENCODE) dstBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)];
759 else dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
762 tjc = new TJCompressor();
763 tjd = new TJDecompressor();
765 for(int pf : formats) {
766 for(int i = 0; i < 2; i++) {
768 if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420
769 || subsamp == TJ.SAMP_440)
770 flags |= TJ.FLAG_FASTUPSAMPLE;
772 if(yuv == YUVDECODE) {
773 tjc.close(); tjd.close(); return;
775 else flags |= TJ.FLAG_BOTTOMUP;
777 size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100,
779 decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags);
780 if(pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi)
781 decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX),
782 baseName, subsamp, flags);
787 if(tjc != null) tjc.close();
788 if(tjd != null) tjd.close();
791 if(tjc != null) tjc.close();
792 if(tjd != null) tjd.close();
795 private static void bufSizeTest() throws Exception {
796 int w, h, i, subsamp;
797 byte[] srcBuf, jpegBuf;
798 TJCompressor tjc = null;
799 Random r = new Random();
802 tjc = new TJCompressor();
803 System.out.println("Buffer size regression test");
804 for(subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) {
805 for(w = 1; w < 48; w++) {
806 int maxh = (w == 1) ? 2048 : 48;
807 for(h = 1; h < maxh; h++) {
809 System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
810 srcBuf = new byte[w * h * 4];
811 jpegBuf = new byte[TJ.bufSize(w, h, subsamp)];
812 for(i = 0; i < w * h * 4; i++) {
813 srcBuf[i] = (byte)(r.nextInt(2) * 255);
815 tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX);
816 tjc.setSubsamp(subsamp);
817 tjc.setJPEGQuality(100);
818 tjc.compress(jpegBuf, 0);
820 srcBuf = new byte[h * w * 4];
821 jpegBuf = new byte[TJ.bufSize(h, w, subsamp)];
822 for(i = 0; i < h * w * 4; i++) {
823 srcBuf[i] = (byte)(r.nextInt(2) * 255);
825 tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX);
826 tjc.compress(jpegBuf, 0);
830 System.out.println("Done. ");
833 if(tjc != null) tjc.close();
836 if(tjc != null) tjc.close();
839 public static void main(String argv[]) {
841 String testName = "javatest";
842 boolean doyuv = false;
843 for(int i = 0; i < argv.length; i++) {
844 if(argv[i].equalsIgnoreCase("-yuv")) doyuv = true;
845 if(argv[i].substring(0, 1).equalsIgnoreCase("-h")
846 || argv[i].equalsIgnoreCase("-?"))
848 if(argv[i].equalsIgnoreCase("-bi")) {
850 testName = "javabitest";
853 if(doyuv) yuv = YUVENCODE;
854 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444, testName);
855 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444, testName);
856 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422,
858 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422,
860 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420,
862 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420,
864 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440,
866 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440,
868 doTest(35, 39, bi ? onlyGrayBI : onlyGray, TJ.SAMP_GRAY, testName);
869 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY,
871 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
873 if(!doyuv && !bi) bufSizeTest();
876 doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0");
877 doTest(35, 39, onlyRGB, TJ.SAMP_444, "javatest_yuv1");
878 doTest(48, 48, onlyRGB, TJ.SAMP_422, "javatest_yuv0");
879 doTest(39, 41, onlyRGB, TJ.SAMP_422, "javatest_yuv1");
880 doTest(48, 48, onlyRGB, TJ.SAMP_420, "javatest_yuv0");
881 doTest(41, 35, onlyRGB, TJ.SAMP_420, "javatest_yuv1");
882 doTest(48, 48, onlyRGB, TJ.SAMP_440, "javatest_yuv0");
883 doTest(35, 39, onlyRGB, TJ.SAMP_440, "javatest_yuv1");
884 doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv0");
885 doTest(35, 39, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv1");
886 doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "javatest_yuv0");
887 doTest(39, 41, onlyGray, TJ.SAMP_GRAY, "javatest_yuv1");
894 System.exit(exitStatus);