TJUnitTest.java revision cac105133e75a52fa5d57a2abccf242bb7b820d0
1/* 2 * Copyright (C)2011-2012 D. R. Commander. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 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. 15 * 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. 27 */ 28 29/* 30 * This program tests the various code paths in the TurboJPEG JNI Wrapper 31 */ 32 33import java.io.*; 34import java.util.*; 35import java.awt.image.*; 36import javax.imageio.*; 37import java.nio.*; 38import org.libjpegturbo.turbojpeg.*; 39 40public class TJUnitTest { 41 42 private static final String classname = 43 new TJUnitTest().getClass().getName(); 44 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"); 50 System.exit(1); 51 } 52 53 private final static String subNameLong[] = { 54 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0" 55 }; 56 private final static String subName[] = { 57 "444", "422", "420", "GRAY", "440" 58 }; 59 60 private final static String pixFormatStr[] = { 61 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale", 62 "RGBA", "BGRA", "ABGR", "ARGB" 63 }; 64 65 private final static int alphaOffset[] = { 66 -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0 67 }; 68 69 private final static int _3byteFormats[] = { 70 TJ.PF_RGB, TJ.PF_BGR 71 }; 72 private final static int _3byteFormatsBI[] = { 73 BufferedImage.TYPE_3BYTE_BGR 74 }; 75 private final static int _4byteFormats[] = { 76 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB 77 }; 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 82 }; 83 private final static int onlyGray[] = { 84 TJ.PF_GRAY 85 }; 86 private final static int onlyGrayBI[] = { 87 BufferedImage.TYPE_BYTE_GRAY 88 }; 89 private final static int onlyRGB[] = { 90 TJ.PF_RGB 91 }; 92 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; 97 98 private static int exitStatus = 0; 99 100 private static int biTypePF(int biType) { 101 ByteOrder byteOrder = ByteOrder.nativeOrder(); 102 switch(biType) { 103 case BufferedImage.TYPE_3BYTE_BGR: 104 return TJ.PF_BGR; 105 case BufferedImage.TYPE_4BYTE_ABGR: 106 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 107 return TJ.PF_XBGR; 108 case BufferedImage.TYPE_BYTE_GRAY: 109 return TJ.PF_GRAY; 110 case BufferedImage.TYPE_INT_BGR: 111 if(byteOrder == ByteOrder.BIG_ENDIAN) 112 return TJ.PF_XBGR; 113 else 114 return TJ.PF_RGBX; 115 case BufferedImage.TYPE_INT_RGB: 116 if(byteOrder == ByteOrder.BIG_ENDIAN) 117 return TJ.PF_XRGB; 118 else 119 return TJ.PF_BGRX; 120 case BufferedImage.TYPE_INT_ARGB: 121 case BufferedImage.TYPE_INT_ARGB_PRE: 122 if(byteOrder == ByteOrder.BIG_ENDIAN) 123 return TJ.PF_ARGB; 124 else 125 return TJ.PF_BGRA; 126 } 127 return 0; 128 } 129 130 private static String biTypeStr(int biType) { 131 switch(biType) { 132 case BufferedImage.TYPE_3BYTE_BGR: 133 return "3BYTE_BGR"; 134 case BufferedImage.TYPE_4BYTE_ABGR: 135 return "4BYTE_ABGR"; 136 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 137 return "4BYTE_ABGR_PRE"; 138 case BufferedImage.TYPE_BYTE_GRAY: 139 return "BYTE_GRAY"; 140 case BufferedImage.TYPE_INT_BGR: 141 return "INT_BGR"; 142 case BufferedImage.TYPE_INT_RGB: 143 return "INT_RGB"; 144 case BufferedImage.TYPE_INT_ARGB: 145 return "INT_ARGB"; 146 case BufferedImage.TYPE_INT_ARGB_PRE: 147 return "INT_ARGB_PRE"; 148 } 149 return "Unknown"; 150 } 151 152 153 private static double getTime() { 154 return (double)System.nanoTime() / 1.0e9; 155 } 156 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; 165 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; 176 } 177 } 178 return; 179 } 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) { 186 if(row < halfway) { 187 buf[index + roffset] = (byte)255; 188 buf[index + goffset] = (byte)255; 189 buf[index + boffset] = (byte)255; 190 } 191 } 192 else { 193 buf[index + roffset] = (byte)255; 194 if(row >= halfway) buf[index + goffset] = (byte)255; 195 } 196 if (aoffset >= 0) buf[index + aoffset] = (byte)255; 197 } 198 } 199 } 200 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; 208 209 Arrays.fill(buf, 0); 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) { 216 if(row < halfway) { 217 buf[index] |= (255 << rshift); 218 buf[index] |= (255 << gshift); 219 buf[index] |= (255 << bshift); 220 } 221 } 222 else { 223 buf[index] |= (255 << rshift); 224 if(row >= halfway) buf[index] |= (255 << gshift); 225 } 226 if (ashift >= 0) buf[index] |= (255 << ashift); 227 } 228 } 229 } 230 231 private static void initImg(BufferedImage img, int pf, int flags) 232 throws Exception { 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); 245 } 246 else { 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); 252 } 253 } 254 255 private static void checkVal(int row, int col, int v, String vname, int cv) 256 throws Exception { 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"); 261 } 262 } 263 264 private static void checkVal0(int row, int col, int v, String vname) 265 throws Exception { 266 v = (v < 0) ? v + 256 : v; 267 if(v > 1) { 268 throw new Exception("\nComp. " + vname + " at " + row + "," + col 269 + " should be 0, not " + v + "\n"); 270 } 271 } 272 273 private static void checkVal255(int row, int col, int v, String vname) 274 throws Exception { 275 v = (v < 0) ? v + 256 : v; 276 if(v < 254) { 277 throw new Exception("\nComp. " + vname + " at " + row + "," + col 278 + " should be 255, not " + v + "\n"); 279 } 280 } 281 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(); 292 293 try { 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) { 304 if(row < halfway) { 305 checkVal255(row, col, r, "R"); 306 checkVal255(row, col, g, "G"); 307 checkVal255(row, col, b, "B"); 308 } 309 else { 310 checkVal0(row, col, r, "R"); 311 checkVal0(row, col, g, "G"); 312 checkVal0(row, col, b, "B"); 313 } 314 } 315 else { 316 if(subsamp == TJ.SAMP_GRAY) { 317 if(row < halfway) { 318 checkVal(row, col, r, "R", 76); 319 checkVal(row, col, g, "G", 76); 320 checkVal(row, col, b, "B", 76); 321 } 322 else { 323 checkVal(row, col, r, "R", 226); 324 checkVal(row, col, g, "G", 226); 325 checkVal(row, col, b, "B", 226); 326 } 327 } 328 else { 329 checkVal255(row, col, r, "R"); 330 if(row < halfway) { 331 checkVal0(row, col, g, "G"); 332 } 333 else { 334 checkVal255(row, col, g, "G"); 335 } 336 checkVal0(row, col, b, "B"); 337 } 338 } 339 checkVal255(row, col, a, "A"); 340 } 341 } 342 } 343 catch(Exception e) { 344 System.out.println(e); 345 retval = 0; 346 } 347 348 if(retval == 0) { 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); 357 } 358 System.out.print("\n"); 359 } 360 } 361 return retval; 362 } 363 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(); 373 374 try { 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) { 385 if(row < halfway) { 386 checkVal255(row, col, r, "R"); 387 checkVal255(row, col, g, "G"); 388 checkVal255(row, col, b, "B"); 389 } 390 else { 391 checkVal0(row, col, r, "R"); 392 checkVal0(row, col, g, "G"); 393 checkVal0(row, col, b, "B"); 394 } 395 } 396 else { 397 if(subsamp == TJ.SAMP_GRAY) { 398 if(row < halfway) { 399 checkVal(row, col, r, "R", 76); 400 checkVal(row, col, g, "G", 76); 401 checkVal(row, col, b, "B", 76); 402 } 403 else { 404 checkVal(row, col, r, "R", 226); 405 checkVal(row, col, g, "G", 226); 406 checkVal(row, col, b, "B", 226); 407 } 408 } 409 else { 410 checkVal255(row, col, r, "R"); 411 if(row < halfway) { 412 checkVal0(row, col, g, "G"); 413 } 414 else { 415 checkVal255(row, col, g, "G"); 416 } 417 checkVal0(row, col, b, "B"); 418 } 419 } 420 checkVal255(row, col, a, "A"); 421 } 422 } 423 } 424 catch(Exception e) { 425 System.out.println(e); 426 retval = 0; 427 } 428 429 if(retval == 0) { 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); 438 } 439 System.out.print("\n"); 440 } 441 } 442 return retval; 443 } 444 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, 459 subsamp, sf, flags); 460 } 461 else { 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, 467 sf, flags); 468 } 469 } 470 471 private static int PAD(int v, int p) { 472 return ((v + (p) - 1) & (~((p) - 1))); 473 } 474 475 private static int checkBufYUV(byte[] buf, int size, int w, int h, 476 int subsamp) throws Exception { 477 int row, col; 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); 482 int retval = 1; 483 int correctsize = ypitch * ph 484 + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2); 485 int halfway = 16; 486 487 try { 488 if(size != correctsize) 489 throw new Exception("\nIncorrect size " + size + ". Should be " 490 + correctsize); 491 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"); 498 } 499 else { 500 if(row < halfway) checkVal(row, col, y, "Y", 76); 501 else checkVal(row, col, y, "Y", 226); 502 } 503 } 504 } 505 if(subsamp != TJ.SAMP_GRAY) { 506 halfway = 16 / vsf; 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); 514 } 515 else { 516 if(row < halfway) { 517 checkVal(row, col, u, "U", 85); 518 checkVal255(row, col, v, "V"); 519 } 520 else { 521 checkVal0(row, col, u, "U"); 522 checkVal(row, col, v, "V", 149); 523 } 524 } 525 } 526 } 527 } 528 } 529 catch(Exception e) { 530 System.out.println(e); 531 retval = 0; 532 } 533 534 if(retval == 0) { 535 for(row = 0; row < ph; row++) { 536 for(col = 0; col < pw; col++) { 537 int y = buf[ypitch * row + col]; 538 if(y < 0) y += 256; 539 System.out.format("%3d ", y); 540 } 541 System.out.print("\n"); 542 } 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)]; 547 if(u < 0) u += 256; 548 System.out.format("%3d ", u); 549 } 550 System.out.print("\n"); 551 } 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)]; 556 if(v < 0) v += 256; 557 System.out.format("%3d ", v); 558 } 559 System.out.print("\n"); 560 } 561 System.out.print("\n"); 562 } 563 564 return retval; 565 } 566 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); 572 fos.close(); 573 } 574 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 { 578 String tempstr; 579 byte[] srcBuf = null; 580 BufferedImage img = null; 581 String pfStr; 582 double t; 583 int size = 0, ps, imgType = pf; 584 585 if (bi) { 586 pf = biTypePF(imgType); 587 pfStr = biTypeStr(imgType); 588 } 589 else pfStr = pixFormatStr[pf]; 590 ps = TJ.getPixelSize(pf); 591 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 + " ... "); 599 600 if(bi) { 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); 608 } 609 else { 610 srcBuf = new byte[w * h * ps + 1]; 611 initBuf(srcBuf, w, w * ps, h, pf, flags); 612 } 613 Arrays.fill(dstBuf, (byte)0); 614 615 t = getTime(); 616 tjc.setSubsamp(subsamp); 617 tjc.setJPEGQuality(jpegQual); 618 if(bi) { 619 if(yuv == YUVENCODE) tjc.encodeYUV(img, dstBuf, flags); 620 else tjc.compress(img, dstBuf, flags); 621 } 622 else { 623 tjc.setSourceImage(srcBuf, w, 0, h, pf); 624 if(yuv == YUVENCODE) tjc.encodeYUV(dstBuf, flags); 625 else tjc.compress(dstBuf, flags); 626 } 627 size = tjc.getCompressedSize(); 628 t = getTime() - t; 629 630 if(yuv == YUVENCODE) 631 tempstr = baseName + "_enc_" + pfStr + "_" 632 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" 633 + subName[subsamp] + ".yuv"; 634 else 635 tempstr = baseName + "_enc_" + pfStr + "_" 636 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" 637 + subName[subsamp] + "_Q" + jpegQual + ".jpg"; 638 writeJPEG(dstBuf, size, tempstr); 639 640 if(yuv == YUVENCODE) { 641 if(checkBufYUV(dstBuf, size, w, h, subsamp) == 1) 642 System.out.print("Passed."); 643 else { 644 System.out.print("FAILED!"); exitStatus = -1; 645 } 646 } 647 else System.out.print("Done."); 648 System.out.format(" %.6f ms\n", t * 1000.); 649 System.out.println(" Result in " + tempstr); 650 651 return size; 652 } 653 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; 658 double t; 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; 664 665 if(yuv == YUVENCODE) return; 666 667 if (bi) { 668 pf = biTypePF(imgType); 669 pfStr = biTypeStr(imgType); 670 } 671 else pfStr = pixFormatStr[pf]; 672 673 System.out.print("JPEG -> "); 674 if(yuv == YUVDECODE) 675 System.out.print("YUV " + subName[subsamp] + " ... "); 676 else { 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 "); 681 if(!sf.isOne()) 682 System.out.print(sf.getNum() + "/" + sf.getDenom() + " ... "); 683 else System.out.print("... "); 684 } 685 686 t = getTime(); 687 tjd.setJPEGImage(jpegBuf, jpegSize); 688 if(tjd.getWidth() != w || tjd.getHeight() != h 689 || tjd.getSubsamp() != subsamp) 690 throw new Exception("Incorrect JPEG header"); 691 692 temp1 = scaledWidth; 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"); 698 699 if(yuv == YUVDECODE) dstBuf = tjd.decompressToYUV(flags); 700 else { 701 if(bi) 702 img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags); 703 else dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags); 704 } 705 t = getTime() - t; 706 707 if(bi) { 708 tempstr = baseName + "_dec_" + pfStr + "_" 709 + (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" 710 + subName[subsamp] + "_" + (double)sf.getNum() / (double)sf.getDenom() 711 + "x" + ".png"; 712 File file = new File(tempstr); 713 ImageIO.write(img, "png", file); 714 } 715 716 if(yuv == YUVDECODE) { 717 if(checkBufYUV(dstBuf, dstBuf.length, w, h, subsamp) == 1) 718 System.out.print("Passed."); 719 else { 720 System.out.print("FAILED!"); exitStatus = -1; 721 } 722 } 723 else { 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."); 728 else { 729 System.out.print("FAILED!"); exitStatus = -1; 730 } 731 } 732 System.out.format(" %.6f ms\n", t * 1000.); 733 } 734 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 { 738 int i; 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, 743 flags, sf[i]); 744 } 745 else 746 decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp, 747 flags, new TJScalingFactor(1, 1)); 748 System.out.print("\n"); 749 } 750 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; 755 int size; 756 byte[] dstBuf; 757 758 if(yuv == YUVENCODE) dstBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)]; 759 else dstBuf = new byte[TJ.bufSize(w, h, subsamp)]; 760 761 try { 762 tjc = new TJCompressor(); 763 tjd = new TJDecompressor(); 764 765 for(int pf : formats) { 766 for(int i = 0; i < 2; i++) { 767 int flags = 0; 768 if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 769 || subsamp == TJ.SAMP_440) 770 flags |= TJ.FLAG_FASTUPSAMPLE; 771 if(i == 1) { 772 if(yuv == YUVDECODE) { 773 tjc.close(); tjd.close(); return; 774 } 775 else flags |= TJ.FLAG_BOTTOMUP; 776 } 777 size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100, 778 flags); 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); 783 } 784 } 785 } 786 catch(Exception e) { 787 if(tjc != null) tjc.close(); 788 if(tjd != null) tjd.close(); 789 throw e; 790 } 791 if(tjc != null) tjc.close(); 792 if(tjd != null) tjd.close(); 793 } 794 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(); 800 801 try { 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++) { 808 if(h % 100 == 0) 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); 814 } 815 tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX); 816 tjc.setSubsamp(subsamp); 817 tjc.setJPEGQuality(100); 818 tjc.compress(jpegBuf, 0); 819 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); 824 } 825 tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX); 826 tjc.compress(jpegBuf, 0); 827 } 828 } 829 } 830 System.out.println("Done. "); 831 } 832 catch(Exception e) { 833 if(tjc != null) tjc.close(); 834 throw e; 835 } 836 if(tjc != null) tjc.close(); 837 } 838 839 public static void main(String argv[]) { 840 try { 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("-?")) 847 usage(); 848 if(argv[i].equalsIgnoreCase("-bi")) { 849 bi = true; 850 testName = "javabitest"; 851 } 852 } 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, 857 testName); 858 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422, 859 testName); 860 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420, 861 testName); 862 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420, 863 testName); 864 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440, 865 testName); 866 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440, 867 testName); 868 doTest(35, 39, bi ? onlyGrayBI : onlyGray, TJ.SAMP_GRAY, testName); 869 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY, 870 testName); 871 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY, 872 testName); 873 if(!doyuv && !bi) bufSizeTest(); 874 if(doyuv && !bi) { 875 yuv = YUVDECODE; 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"); 888 } 889 } 890 catch(Exception e) { 891 e.printStackTrace(); 892 exitStatus = -1; 893 } 894 System.exit(exitStatus); 895 } 896} 897