2 * Copyright (C)2011-2018 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 @SuppressWarnings("checkstyle:JavadocType")
41 final class TJUnitTest {
43 private TJUnitTest() {}
45 static final String CLASS_NAME =
46 new TJUnitTest().getClass().getName();
49 System.out.println("\nUSAGE: java " + CLASS_NAME + " [options]\n");
50 System.out.println("Options:");
51 System.out.println("-yuv = test YUV encoding/decoding support");
52 System.out.println("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest");
53 System.out.println(" 4-byte boundary");
54 System.out.println("-bi = test BufferedImage support\n");
58 static final String[] SUBNAME_LONG = {
59 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1"
61 static final String[] SUBNAME = {
62 "444", "422", "420", "GRAY", "440", "411"
65 static final String[] PIXFORMATSTR = {
66 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale",
67 "RGBA", "BGRA", "ABGR", "ARGB", "CMYK"
70 static final int[] FORMATS_3BYTE = {
73 static final int[] FORMATS_3BYTEBI = {
74 BufferedImage.TYPE_3BYTE_BGR
76 static final int[] FORMATS_4BYTE = {
77 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB, TJ.PF_CMYK
79 static final int[] FORMATS_4BYTEBI = {
80 BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_INT_RGB,
81 BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE,
82 BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE
84 static final int[] FORMATS_GRAY = {
87 static final int[] FORMATS_GRAYBI = {
88 BufferedImage.TYPE_BYTE_GRAY
90 static final int[] FORMATS_RGB = {
94 private static boolean doYUV = false;
95 private static int pad = 4;
96 private static boolean bi = false;
98 private static int exitStatus = 0;
100 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:
112 case BufferedImage.TYPE_INT_RGB:
114 case BufferedImage.TYPE_INT_ARGB:
115 case BufferedImage.TYPE_INT_ARGB_PRE:
122 static String biTypeStr(int biType) {
124 case BufferedImage.TYPE_3BYTE_BGR:
126 case BufferedImage.TYPE_4BYTE_ABGR:
128 case BufferedImage.TYPE_4BYTE_ABGR_PRE:
129 return "4BYTE_ABGR_PRE";
130 case BufferedImage.TYPE_BYTE_GRAY:
132 case BufferedImage.TYPE_INT_BGR:
134 case BufferedImage.TYPE_INT_RGB:
136 case BufferedImage.TYPE_INT_ARGB:
138 case BufferedImage.TYPE_INT_ARGB_PRE:
139 return "INT_ARGB_PRE";
145 static void initBuf(byte[] buf, int w, int pitch, int h, int pf, int flags)
147 int roffset = TJ.getRedOffset(pf);
148 int goffset = TJ.getGreenOffset(pf);
149 int boffset = TJ.getBlueOffset(pf);
150 int aoffset = TJ.getAlphaOffset(pf);
151 int ps = TJ.getPixelSize(pf);
152 int index, row, col, halfway = 16;
154 if (pf == TJ.PF_GRAY) {
155 Arrays.fill(buf, (byte)0);
156 for (row = 0; row < h; row++) {
157 for (col = 0; col < w; col++) {
158 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
159 index = pitch * (h - row - 1) + col;
161 index = pitch * row + col;
162 if (((row / 8) + (col / 8)) % 2 == 0)
163 buf[index] = (row < halfway) ? (byte)255 : 0;
165 buf[index] = (row < halfway) ? 76 : (byte)226;
170 if (pf == TJ.PF_CMYK) {
171 Arrays.fill(buf, (byte)255);
172 for (row = 0; row < h; row++) {
173 for (col = 0; col < w; col++) {
174 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
175 index = (h - row - 1) * w + col;
177 index = row * w + col;
178 if (((row / 8) + (col / 8)) % 2 == 0) {
179 if (row >= halfway) buf[index * ps + 3] = 0;
181 buf[index * ps + 2] = 0;
183 buf[index * ps + 1] = 0;
190 Arrays.fill(buf, (byte)0);
191 for (row = 0; row < h; row++) {
192 for (col = 0; col < w; col++) {
193 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
194 index = pitch * (h - row - 1) + col * ps;
196 index = pitch * row + col * ps;
197 if (((row / 8) + (col / 8)) % 2 == 0) {
199 buf[index + roffset] = (byte)255;
200 buf[index + goffset] = (byte)255;
201 buf[index + boffset] = (byte)255;
204 buf[index + roffset] = (byte)255;
206 buf[index + goffset] = (byte)255;
209 buf[index + aoffset] = (byte)255;
214 static void initIntBuf(int[] buf, int w, int pitch, int h, int pf, int flags)
216 int rshift = TJ.getRedOffset(pf) * 8;
217 int gshift = TJ.getGreenOffset(pf) * 8;
218 int bshift = TJ.getBlueOffset(pf) * 8;
219 int ashift = TJ.getAlphaOffset(pf) * 8;
220 int index, row, col, halfway = 16;
223 for (row = 0; row < h; row++) {
224 for (col = 0; col < w; col++) {
225 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
226 index = pitch * (h - row - 1) + col;
228 index = pitch * row + col;
229 if (((row / 8) + (col / 8)) % 2 == 0) {
231 buf[index] |= (255 << rshift);
232 buf[index] |= (255 << gshift);
233 buf[index] |= (255 << bshift);
236 buf[index] |= (255 << rshift);
238 buf[index] |= (255 << gshift);
241 buf[index] |= (255 << ashift);
246 static void initImg(BufferedImage img, int pf, int flags) throws Exception {
247 WritableRaster wr = img.getRaster();
248 int imgType = img.getType();
250 if (imgType == BufferedImage.TYPE_INT_RGB ||
251 imgType == BufferedImage.TYPE_INT_BGR ||
252 imgType == BufferedImage.TYPE_INT_ARGB ||
253 imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
254 SinglePixelPackedSampleModel sm =
255 (SinglePixelPackedSampleModel)img.getSampleModel();
256 int pitch = sm.getScanlineStride();
257 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
258 int[] buf = db.getData();
259 initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
261 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
262 int pitch = sm.getScanlineStride();
263 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
264 byte[] buf = db.getData();
265 initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags);
269 static void checkVal(int row, int col, int v, String vname, int cv)
271 v = (v < 0) ? v + 256 : v;
272 if (v < cv - 1 || v > cv + 1) {
273 throw new Exception("Comp. " + vname + " at " + row + "," + col +
274 " should be " + cv + ", not " + v);
278 static void checkVal0(int row, int col, int v, String vname)
280 v = (v < 0) ? v + 256 : v;
282 throw new Exception("Comp. " + vname + " at " + row + "," + col +
283 " should be 0, not " + v);
287 static void checkVal255(int row, int col, int v, String vname)
289 v = (v < 0) ? v + 256 : v;
291 throw new Exception("Comp. " + vname + " at " + row + "," + col +
292 " should be 255, not " + v);
296 static int checkBuf(byte[] buf, int w, int pitch, int h, int pf, int subsamp,
297 TJScalingFactor sf, int flags) throws Exception {
298 int roffset = TJ.getRedOffset(pf);
299 int goffset = TJ.getGreenOffset(pf);
300 int boffset = TJ.getBlueOffset(pf);
301 int aoffset = TJ.getAlphaOffset(pf);
302 int ps = TJ.getPixelSize(pf);
303 int index, row, col, retval = 1;
304 int halfway = 16 * sf.getNum() / sf.getDenom();
305 int blockSize = 8 * sf.getNum() / sf.getDenom();
309 if (pf == TJ.PF_GRAY)
310 roffset = goffset = boffset = 0;
312 if (pf == TJ.PF_CMYK) {
313 for (row = 0; row < h; row++) {
314 for (col = 0; col < w; col++) {
315 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
316 index = (h - row - 1) * w + col;
318 index = row * w + col;
319 byte c = buf[index * ps];
320 byte m = buf[index * ps + 1];
321 byte y = buf[index * ps + 2];
322 byte k = buf[index * ps + 3];
323 checkVal255(row, col, c, "C");
324 if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
325 checkVal255(row, col, m, "M");
326 checkVal255(row, col, y, "Y");
328 checkVal255(row, col, k, "K");
330 checkVal0(row, col, k, "K");
332 checkVal0(row, col, y, "Y");
333 checkVal255(row, col, k, "K");
335 checkVal0(row, col, m, "M");
337 checkVal255(row, col, m, "M");
344 for (row = 0; row < halfway; row++) {
345 for (col = 0; col < w; col++) {
346 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
347 index = pitch * (h - row - 1) + col * ps;
349 index = pitch * row + col * ps;
350 byte r = buf[index + roffset];
351 byte g = buf[index + goffset];
352 byte b = buf[index + boffset];
353 byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255;
354 if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
356 checkVal255(row, col, r, "R");
357 checkVal255(row, col, g, "G");
358 checkVal255(row, col, b, "B");
360 checkVal0(row, col, r, "R");
361 checkVal0(row, col, g, "G");
362 checkVal0(row, col, b, "B");
365 if (subsamp == TJ.SAMP_GRAY) {
367 checkVal(row, col, r, "R", 76);
368 checkVal(row, col, g, "G", 76);
369 checkVal(row, col, b, "B", 76);
371 checkVal(row, col, r, "R", 226);
372 checkVal(row, col, g, "G", 226);
373 checkVal(row, col, b, "B", 226);
376 checkVal255(row, col, r, "R");
378 checkVal0(row, col, g, "G");
380 checkVal255(row, col, g, "G");
382 checkVal0(row, col, b, "B");
385 checkVal255(row, col, a, "A");
388 } catch (Exception e) {
389 System.out.println("\n" + e.getMessage());
394 for (row = 0; row < h; row++) {
395 for (col = 0; col < w; col++) {
396 if (pf == TJ.PF_CMYK) {
397 int c = buf[pitch * row + col * ps];
398 int m = buf[pitch * row + col * ps + 1];
399 int y = buf[pitch * row + col * ps + 2];
400 int k = buf[pitch * row + col * ps + 3];
405 System.out.format("%3d/%3d/%3d/%3d ", c, m, y, k);
407 int r = buf[pitch * row + col * ps + roffset];
408 int g = buf[pitch * row + col * ps + goffset];
409 int b = buf[pitch * row + col * ps + boffset];
413 System.out.format("%3d/%3d/%3d ", r, g, b);
416 System.out.print("\n");
422 static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf,
423 int subsamp, TJScalingFactor sf, int flags)
425 int rshift = TJ.getRedOffset(pf) * 8;
426 int gshift = TJ.getGreenOffset(pf) * 8;
427 int bshift = TJ.getBlueOffset(pf) * 8;
428 int ashift = TJ.getAlphaOffset(pf) * 8;
429 int index, row, col, retval = 1;
430 int halfway = 16 * sf.getNum() / sf.getDenom();
431 int blockSize = 8 * sf.getNum() / sf.getDenom();
434 for (row = 0; row < halfway; row++) {
435 for (col = 0; col < w; col++) {
436 if ((flags & TJ.FLAG_BOTTOMUP) != 0)
437 index = pitch * (h - row - 1) + col;
439 index = pitch * row + col;
440 int r = (buf[index] >> rshift) & 0xFF;
441 int g = (buf[index] >> gshift) & 0xFF;
442 int b = (buf[index] >> bshift) & 0xFF;
443 int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255;
444 if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
446 checkVal255(row, col, r, "R");
447 checkVal255(row, col, g, "G");
448 checkVal255(row, col, b, "B");
450 checkVal0(row, col, r, "R");
451 checkVal0(row, col, g, "G");
452 checkVal0(row, col, b, "B");
455 if (subsamp == TJ.SAMP_GRAY) {
457 checkVal(row, col, r, "R", 76);
458 checkVal(row, col, g, "G", 76);
459 checkVal(row, col, b, "B", 76);
461 checkVal(row, col, r, "R", 226);
462 checkVal(row, col, g, "G", 226);
463 checkVal(row, col, b, "B", 226);
466 checkVal255(row, col, r, "R");
468 checkVal0(row, col, g, "G");
470 checkVal255(row, col, g, "G");
472 checkVal0(row, col, b, "B");
475 checkVal255(row, col, a, "A");
478 } catch (Exception e) {
479 System.out.println("\n" + e.getMessage());
484 for (row = 0; row < h; row++) {
485 for (col = 0; col < w; col++) {
486 int r = (buf[pitch * row + col] >> rshift) & 0xFF;
487 int g = (buf[pitch * row + col] >> gshift) & 0xFF;
488 int b = (buf[pitch * row + col] >> bshift) & 0xFF;
492 System.out.format("%3d/%3d/%3d ", r, g, b);
494 System.out.print("\n");
500 static int checkImg(BufferedImage img, int pf, int subsamp,
501 TJScalingFactor sf, int flags) throws Exception {
502 WritableRaster wr = img.getRaster();
503 int imgType = img.getType();
504 if (imgType == BufferedImage.TYPE_INT_RGB ||
505 imgType == BufferedImage.TYPE_INT_BGR ||
506 imgType == BufferedImage.TYPE_INT_ARGB ||
507 imgType == BufferedImage.TYPE_INT_ARGB_PRE) {
508 SinglePixelPackedSampleModel sm =
509 (SinglePixelPackedSampleModel)img.getSampleModel();
510 int pitch = sm.getScanlineStride();
511 DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
512 int[] buf = db.getData();
513 return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
516 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel();
517 int pitch = sm.getScanlineStride();
518 DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
519 byte[] buf = db.getData();
520 return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
525 static int pad(int v, int p) {
526 return ((v + (p) - 1) & (~((p) - 1)));
529 static int checkBufYUV(byte[] buf, int size, int w, int h, int subsamp,
530 TJScalingFactor sf) throws Exception {
532 int hsf = TJ.getMCUWidth(subsamp) / 8, vsf = TJ.getMCUHeight(subsamp) / 8;
533 int pw = pad(w, hsf), ph = pad(h, vsf);
534 int cw = pw / hsf, ch = ph / vsf;
535 int ypitch = pad(pw, pad), uvpitch = pad(cw, pad);
537 int correctsize = ypitch * ph +
538 (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2);
539 int halfway = 16 * sf.getNum() / sf.getDenom();
540 int blockSize = 8 * sf.getNum() / sf.getDenom();
543 if (size != correctsize)
544 throw new Exception("Incorrect size " + size + ". Should be " +
547 for (row = 0; row < ph; row++) {
548 for (col = 0; col < pw; col++) {
549 byte y = buf[ypitch * row + col];
550 if (((row / blockSize) + (col / blockSize)) % 2 == 0) {
552 checkVal255(row, col, y, "Y");
554 checkVal0(row, col, y, "Y");
557 checkVal(row, col, y, "Y", 76);
559 checkVal(row, col, y, "Y", 226);
563 if (subsamp != TJ.SAMP_GRAY) {
564 halfway = 16 / vsf * sf.getNum() / sf.getDenom();
565 for (row = 0; row < ch; row++) {
566 for (col = 0; col < cw; col++) {
567 byte u = buf[ypitch * ph + (uvpitch * row + col)],
568 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
569 if (((row * vsf / blockSize) + (col * hsf / blockSize)) % 2 == 0) {
570 checkVal(row, col, u, "U", 128);
571 checkVal(row, col, v, "V", 128);
574 checkVal(row, col, u, "U", 85);
575 checkVal255(row, col, v, "V");
577 checkVal0(row, col, u, "U");
578 checkVal(row, col, v, "V", 149);
584 } catch (Exception e) {
585 System.out.println("\n" + e.getMessage());
590 for (row = 0; row < ph; row++) {
591 for (col = 0; col < pw; col++) {
592 int y = buf[ypitch * row + col];
594 System.out.format("%3d ", y);
596 System.out.print("\n");
598 System.out.print("\n");
599 for (row = 0; row < ch; row++) {
600 for (col = 0; col < cw; col++) {
601 int u = buf[ypitch * ph + (uvpitch * row + col)];
603 System.out.format("%3d ", u);
605 System.out.print("\n");
607 System.out.print("\n");
608 for (row = 0; row < ch; row++) {
609 for (col = 0; col < cw; col++) {
610 int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)];
612 System.out.format("%3d ", v);
614 System.out.print("\n");
621 static void writeJPEG(byte[] jpegBuf, int jpegBufSize, String filename)
623 File file = new File(filename);
624 FileOutputStream fos = new FileOutputStream(file);
625 fos.write(jpegBuf, 0, jpegBufSize);
629 static int compTest(TJCompressor tjc, byte[] dstBuf, int w, int h, int pf,
630 String baseName, int subsamp, int jpegQual, int flags)
633 byte[] srcBuf = null;
634 BufferedImage img = null;
635 String pfStr, pfStrLong;
636 String buStr = (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD";
637 String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
638 "Bottom-Up" : "Top-Down ";
639 int size = 0, ps, imgType = pf;
642 pf = biTypePF(imgType);
643 pfStr = biTypeStr(imgType);
644 pfStrLong = pfStr + " (" + PIXFORMATSTR[pf] + ")";
646 pfStr = PIXFORMATSTR[pf];
649 ps = TJ.getPixelSize(pf);
652 img = new BufferedImage(w, h, imgType);
653 initImg(img, pf, flags);
654 tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
655 SUBNAME[subsamp] + "_Q" + jpegQual + ".png";
656 File file = new File(tempStr);
657 ImageIO.write(img, "png", file);
658 tjc.setSourceImage(img, 0, 0, 0, 0);
660 srcBuf = new byte[w * h * ps + 1];
661 initBuf(srcBuf, w, w * ps, h, pf, flags);
662 tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, pf);
664 Arrays.fill(dstBuf, (byte)0);
666 tjc.setSubsamp(subsamp);
667 tjc.setJPEGQuality(jpegQual);
669 System.out.format("%s %s -> YUV %s ... ", pfStrLong, buStrLong,
670 SUBNAME_LONG[subsamp]);
671 YUVImage yuvImage = tjc.encodeYUV(pad, flags);
672 if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), w, h, subsamp,
673 new TJScalingFactor(1, 1)) == 1)
674 System.out.print("Passed.\n");
676 System.out.print("FAILED!\n");
680 System.out.format("YUV %s %s -> JPEG Q%d ... ", SUBNAME_LONG[subsamp],
681 buStrLong, jpegQual);
682 tjc.setSourceImage(yuvImage);
684 System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong,
685 SUBNAME_LONG[subsamp], jpegQual);
687 tjc.compress(dstBuf, flags);
688 size = tjc.getCompressedSize();
690 tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" +
691 SUBNAME[subsamp] + "_Q" + jpegQual + ".jpg";
692 writeJPEG(dstBuf, size, tempStr);
693 System.out.println("Done.\n Result in " + tempStr);
698 static void decompTest(TJDecompressor tjd, byte[] jpegBuf, int jpegSize,
699 int w, int h, int pf, String baseName, int subsamp,
700 int flags, TJScalingFactor sf) throws Exception {
701 String pfStr, pfStrLong, tempStr;
702 String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ?
703 "Bottom-Up" : "Top-Down ";
704 int scaledWidth = sf.getScaled(w);
705 int scaledHeight = sf.getScaled(h);
706 int temp1, temp2, imgType = pf;
707 BufferedImage img = null;
708 byte[] dstBuf = null;
711 pf = biTypePF(imgType);
712 pfStr = biTypeStr(imgType);
713 pfStrLong = pfStr + " (" + PIXFORMATSTR[pf] + ")";
715 pfStr = PIXFORMATSTR[pf];
719 tjd.setSourceImage(jpegBuf, jpegSize);
720 if (tjd.getWidth() != w || tjd.getHeight() != h ||
721 tjd.getSubsamp() != subsamp)
722 throw new Exception("Incorrect JPEG header");
725 temp2 = scaledHeight;
726 temp1 = tjd.getScaledWidth(temp1, temp2);
727 temp2 = tjd.getScaledHeight(temp1, temp2);
728 if (temp1 != scaledWidth || temp2 != scaledHeight)
729 throw new Exception("Scaled size mismatch");
732 System.out.format("JPEG -> YUV %s ", SUBNAME_LONG[subsamp]);
734 System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom());
735 else System.out.print("... ");
736 YUVImage yuvImage = tjd.decompressToYUV(scaledWidth, pad, scaledHeight,
738 if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), scaledWidth,
739 scaledHeight, subsamp, sf) == 1)
740 System.out.print("Passed.\n");
742 System.out.print("FAILED!\n"); exitStatus = -1;
745 System.out.format("YUV %s -> %s %s ... ", SUBNAME_LONG[subsamp],
746 pfStrLong, buStrLong);
747 tjd.setSourceImage(yuvImage);
749 System.out.format("JPEG -> %s %s ", pfStrLong, buStrLong);
751 System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom());
752 else System.out.print("... ");
755 img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags);
757 dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags);
760 tempStr = baseName + "_dec_" + pfStr + "_" +
761 (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" +
762 SUBNAME[subsamp] + "_" +
763 (double)sf.getNum() / (double)sf.getDenom() + "x" + ".png";
764 File file = new File(tempStr);
765 ImageIO.write(img, "png", file);
768 if ((bi && checkImg(img, pf, subsamp, sf, flags) == 1) ||
769 (!bi && checkBuf(dstBuf, scaledWidth,
770 scaledWidth * TJ.getPixelSize(pf), scaledHeight, pf,
771 subsamp, sf, flags) == 1))
772 System.out.print("Passed.\n");
774 System.out.print("FAILED!\n");
779 static void decompTest(TJDecompressor tjd, byte[] jpegBuf, int jpegSize,
780 int w, int h, int pf, String baseName, int subsamp,
781 int flags) throws Exception {
783 TJScalingFactor[] sf = TJ.getScalingFactors();
784 for (i = 0; i < sf.length; i++) {
785 int num = sf[i].getNum();
786 int denom = sf[i].getDenom();
787 if (subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY ||
788 (subsamp == TJ.SAMP_411 && num == 1 &&
789 (denom == 2 || denom == 1)) ||
790 (subsamp != TJ.SAMP_411 && num == 1 &&
791 (denom == 4 || denom == 2 || denom == 1)))
792 decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp,
797 static void doTest(int w, int h, int[] formats, int subsamp, String baseName)
799 TJCompressor tjc = null;
800 TJDecompressor tjd = null;
804 dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
807 tjc = new TJCompressor();
808 tjd = new TJDecompressor();
810 for (int pf : formats) {
811 if (pf < 0) continue;
812 for (int i = 0; i < 2; i++) {
814 if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 ||
815 subsamp == TJ.SAMP_440 || subsamp == TJ.SAMP_411)
816 flags |= TJ.FLAG_FASTUPSAMPLE;
818 flags |= TJ.FLAG_BOTTOMUP;
819 size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100,
821 decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags);
822 if (pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi) {
823 System.out.print("\n");
824 decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX),
825 baseName, subsamp, flags);
827 System.out.print("\n");
830 System.out.print("--------------------\n\n");
831 } catch (Exception e) {
832 if (tjc != null) tjc.close();
833 if (tjd != null) tjd.close();
836 if (tjc != null) tjc.close();
837 if (tjd != null) tjd.close();
840 static void bufSizeTest() throws Exception {
841 int w, h, i, subsamp;
842 byte[] srcBuf, dstBuf = null;
843 YUVImage dstImage = null;
844 TJCompressor tjc = null;
845 Random r = new Random();
848 tjc = new TJCompressor();
849 System.out.println("Buffer size regression test");
850 for (subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) {
851 for (w = 1; w < 48; w++) {
852 int maxh = (w == 1) ? 2048 : 48;
853 for (h = 1; h < maxh; h++) {
855 System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
856 srcBuf = new byte[w * h * 4];
858 dstImage = new YUVImage(w, pad, h, subsamp);
860 dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
861 for (i = 0; i < w * h * 4; i++) {
862 srcBuf[i] = (byte)(r.nextInt(2) * 255);
864 tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, TJ.PF_BGRX);
865 tjc.setSubsamp(subsamp);
866 tjc.setJPEGQuality(100);
868 tjc.encodeYUV(dstImage, 0);
870 tjc.compress(dstBuf, 0);
872 srcBuf = new byte[h * w * 4];
874 dstImage = new YUVImage(h, pad, w, subsamp);
876 dstBuf = new byte[TJ.bufSize(h, w, subsamp)];
877 for (i = 0; i < h * w * 4; i++) {
878 srcBuf[i] = (byte)(r.nextInt(2) * 255);
880 tjc.setSourceImage(srcBuf, 0, 0, h, 0, w, TJ.PF_BGRX);
882 tjc.encodeYUV(dstImage, 0);
884 tjc.compress(dstBuf, 0);
891 System.out.println("Done. ");
892 } catch (Exception e) {
893 if (tjc != null) tjc.close();
896 if (tjc != null) tjc.close();
899 public static void main(String[] argv) {
901 String testName = "javatest";
902 for (int i = 0; i < argv.length; i++) {
903 if (argv[i].equalsIgnoreCase("-yuv"))
905 else if (argv[i].equalsIgnoreCase("-noyuvpad"))
907 else if (argv[i].equalsIgnoreCase("-bi")) {
909 testName = "javabitest";
914 FORMATS_4BYTE[4] = -1;
915 doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_444,
917 doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_444,
919 doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_422,
921 doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_422,
923 doTest(39, 41, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_420,
925 doTest(41, 35, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_420,
927 doTest(35, 39, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_440,
929 doTest(39, 41, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_440,
931 doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_411,
933 doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_411,
935 doTest(39, 41, bi ? FORMATS_GRAYBI : FORMATS_GRAY, TJ.SAMP_GRAY,
937 doTest(41, 35, bi ? FORMATS_3BYTEBI : FORMATS_3BYTE, TJ.SAMP_GRAY,
939 FORMATS_4BYTE[4] = -1;
940 doTest(35, 39, bi ? FORMATS_4BYTEBI : FORMATS_4BYTE, TJ.SAMP_GRAY,
945 System.out.print("\n--------------------\n\n");
946 doTest(48, 48, FORMATS_RGB, TJ.SAMP_444, "javatest_yuv0");
947 doTest(48, 48, FORMATS_RGB, TJ.SAMP_422, "javatest_yuv0");
948 doTest(48, 48, FORMATS_RGB, TJ.SAMP_420, "javatest_yuv0");
949 doTest(48, 48, FORMATS_RGB, TJ.SAMP_440, "javatest_yuv0");
950 doTest(48, 48, FORMATS_RGB, TJ.SAMP_411, "javatest_yuv0");
951 doTest(48, 48, FORMATS_RGB, TJ.SAMP_GRAY, "javatest_yuv0");
952 doTest(48, 48, FORMATS_GRAY, TJ.SAMP_GRAY, "javatest_yuv0");
954 } catch (Exception e) {
958 System.exit(exitStatus);