TJUnitTest.java revision 2e2358eae408d1a04e74c4544e9997c507387b4c
1/* 2 * Copyright (C)2011 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 org.libjpegturbo.turbojpeg.*; 38 39public class TJUnitTest { 40 41 private static final String classname = 42 new TJUnitTest().getClass().getName(); 43 44 private static void usage() { 45 System.out.println("\nUSAGE: java " + classname + " [options]\n"); 46 System.out.println("Options:\n"); 47 System.out.println("-yuv = test YUV encoding/decoding support\n"); 48 System.out.println("-bi = test BufferedImage support\n"); 49 System.exit(1); 50 } 51 52 private final static String subNameLong[] = { 53 "4:4:4", "4:2:2", "4:2:0", "GRAY" 54 }; 55 private final static String subName[] = { 56 "444", "422", "420", "GRAY" 57 }; 58 private final static int horizSampFactor[] = { 59 1, 2, 2, 1 60 }; 61 private final static int vertSampFactor[] = { 62 1, 1, 2, 1 63 }; 64 65 private final static String pixFormatStr[] = { 66 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale" 67 }; 68 private final static int biType[] = { 69 0, BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_INT_BGR, 70 BufferedImage.TYPE_INT_RGB, 0, 0, BufferedImage.TYPE_BYTE_GRAY 71 }; 72 73 private final static int _3byteFormats[] = { 74 TJ.PF_RGB, TJ.PF_BGR 75 }; 76 private final static int _3byteFormatsBI[] = { 77 TJ.PF_BGR 78 }; 79 private final static int _4byteFormats[] = { 80 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB 81 }; 82 private final static int _4byteFormatsBI[] = { 83 TJ.PF_RGBX, TJ.PF_BGRX 84 }; 85 private final static int onlyGray[] = { 86 TJ.PF_GRAY 87 }; 88 private final static int onlyRGB[] = { 89 TJ.PF_RGB 90 }; 91 92 private final static int YUVENCODE = 1; 93 private final static int YUVDECODE = 2; 94 private static int yuv = 0; 95 private static boolean bi = false; 96 97 private static int exitStatus = 0; 98 99 private static double getTime() { 100 return (double)System.nanoTime() / 1.0e9; 101 } 102 103 private final static byte pixels[][] = { 104 {0, (byte)255, 0}, 105 {(byte)255, 0, (byte)255}, 106 {(byte)255, (byte)255, 0}, 107 {0, 0, (byte)255}, 108 {0, (byte)255, (byte)255}, 109 {(byte)255, 0, 0}, 110 {(byte)255, (byte)255, (byte)255}, 111 {0, 0, 0}, 112 {(byte)255, 0, 0} 113 }; 114 115 private static void initBuf(byte[] buf, int w, int pitch, int h, int pf, 116 int flags) throws Exception { 117 int roffset = TJ.getRedShift(pf) / 8; 118 int goffset = TJ.getGreenShift(pf) / 8; 119 int boffset = TJ.getBlueShift(pf) / 8; 120 int ps = TJ.getPixelSize(pf); 121 int i, _i, j; 122 123 Arrays.fill(buf, (byte)0); 124 if(pf == TJ.PF_GRAY) { 125 for(_i = 0; _i < 16; _i++) { 126 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 127 else i = _i; 128 for(j = 0; j < w; j++) { 129 if(((_i / 8) + (j / 8)) % 2 == 0) buf[pitch * i + j] = (byte)255; 130 else buf[pitch * i + j] = 76; 131 } 132 } 133 for(_i = 16; _i < h; _i++) { 134 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 135 else i = _i; 136 for(j = 0; j < w; j++) { 137 if(((_i / 8) + (j / 8)) % 2 == 0) buf[pitch * i + j] = 0; 138 else buf[pitch * i + j] = (byte)226; 139 } 140 } 141 return; 142 } 143 for(_i = 0; _i < 16; _i++) { 144 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 145 else i = _i; 146 for(j = 0; j < w; j++) { 147 buf[pitch * i + j * ps + roffset] = (byte)255; 148 if(((_i / 8) + (j / 8)) % 2 == 0) { 149 buf[pitch * i + j * ps + goffset] = (byte)255; 150 buf[pitch * i + j * ps + boffset] = (byte)255; 151 } 152 } 153 } 154 for(_i = 16; _i < h; _i++) { 155 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 156 else i = _i; 157 for(j = 0; j < w; j++) { 158 if(((_i / 8) + (j / 8)) % 2 != 0) { 159 buf[pitch * i + j * ps + roffset] = (byte)255; 160 buf[pitch * i + j * ps + goffset] = (byte)255; 161 } 162 } 163 } 164 } 165 166 private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf, 167 int flags) throws Exception { 168 int rshift = TJ.getRedShift(pf); 169 int gshift = TJ.getGreenShift(pf); 170 int bshift = TJ.getBlueShift(pf); 171 int i, _i, j; 172 173 Arrays.fill(buf, 0); 174 for(_i = 0; _i < 16; _i++) { 175 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 176 else i = _i; 177 for(j = 0; j < w; j++) { 178 buf[pitch * i + j] = (255 << rshift); 179 if(((_i / 8) + (j / 8)) % 2 == 0) { 180 buf[pitch * i + j] |= (255 << gshift); 181 buf[pitch * i + j] |= (255 << bshift); 182 } 183 } 184 } 185 for(_i = 16; _i < h; _i++) { 186 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 187 else i = _i; 188 for(j = 0; j < w; j++) { 189 if(((_i / 8) + (j / 8)) % 2 != 0) { 190 buf[pitch * i + j] = (255 << rshift); 191 buf[pitch * i + j] |= (255 << gshift); 192 } 193 } 194 } 195 } 196 197 private static void initImg(BufferedImage img, int pf, int flags) 198 throws Exception { 199 WritableRaster wr = img.getRaster(); 200 int imgtype = img.getType(); 201 if(imgtype == BufferedImage.TYPE_INT_RGB 202 || imgtype == BufferedImage.TYPE_INT_BGR) { 203 SinglePixelPackedSampleModel sm = 204 (SinglePixelPackedSampleModel)img.getSampleModel(); 205 int pitch = sm.getScanlineStride(); 206 DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); 207 int[] buf = db.getData(); 208 initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags); 209 } 210 else { 211 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel(); 212 int pitch = sm.getScanlineStride(); 213 DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); 214 byte[] buf = db.getData(); 215 initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags); 216 } 217 } 218 219 private static void checkVal(int i, int j, int v, String vname, int cv) 220 throws Exception { 221 v = (v < 0) ? v + 256 : v; 222 if(v < cv - 1 || v > cv + 1) { 223 throw new Exception("\nComp. " + vname + " at " + i + "," + j 224 + " should be " + cv + ", not " + v + "\n"); 225 } 226 } 227 228 private static void checkVal0(int i, int j, int v, String vname) 229 throws Exception { 230 v = (v < 0) ? v + 256 : v; 231 if(v > 1) { 232 throw new Exception("\nComp. " + vname + " at " + i + "," + j 233 + " should be 0, not " + v + "\n"); 234 } 235 } 236 237 private static void checkVal255(int i, int j, int v, String vname) 238 throws Exception { 239 v = (v < 0) ? v + 256 : v; 240 if(v < 254) { 241 throw new Exception("\nComp. " + vname + " at " + i + "," + j 242 + " should be 255, not " + v + "\n"); 243 } 244 } 245 246 private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf, 247 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception { 248 int roffset = TJ.getRedShift(pf) / 8; 249 int goffset = TJ.getGreenShift(pf) / 8; 250 int boffset = TJ.getBlueShift(pf) / 8; 251 int ps = TJ.getPixelSize(pf); 252 int i, _i, j, retval = 1; 253 int halfway = 16 * scaleNum / scaleDenom; 254 int blockSize = 8 * scaleNum / scaleDenom; 255 256 try { 257 for(_i = 0; _i < halfway; _i++) { 258 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 259 else i = _i; 260 for(j = 0; j < w; j++) { 261 byte r = buf[pitch * i + j * ps + roffset]; 262 byte g = buf[pitch * i + j * ps + goffset]; 263 byte b = buf[pitch * i + j * ps + boffset]; 264 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) { 265 checkVal255(_i, j, r, "R"); 266 checkVal255(_i, j, g, "G"); 267 checkVal255(_i, j, b, "B"); 268 } 269 else { 270 if(subsamp == TJ.SAMP_GRAY) { 271 checkVal(_i, j, r, "R", 76); 272 checkVal(_i, j, g, "G", 76); 273 checkVal(_i, j, b, "B", 76); 274 } 275 else { 276 checkVal255(_i, j, r, "R"); 277 checkVal0(_i, j, g, "G"); 278 checkVal0(_i, j, b, "B"); 279 } 280 } 281 } 282 } 283 for(_i = halfway; _i < h; _i++) { 284 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 285 else i = _i; 286 for(j = 0; j < w; j++) { 287 byte r = buf[pitch * i + j * ps + roffset]; 288 byte g = buf[pitch * i + j * ps + goffset]; 289 byte b = buf[pitch * i + j * ps + boffset]; 290 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) { 291 checkVal0(_i, j, r, "R"); 292 checkVal0(_i, j, g, "G"); 293 } 294 else { 295 if(subsamp == TJ.SAMP_GRAY) { 296 checkVal(_i, j, r, "R", 226); 297 checkVal(_i, j, g, "G", 226); 298 checkVal(_i, j, b, "B", 226); 299 } 300 else { 301 checkVal255(_i, j, r, "R"); 302 checkVal255(_i, j, g, "G"); 303 checkVal0(_i, j, b, "B"); 304 } 305 } 306 } 307 } 308 } 309 catch(Exception e) { 310 System.out.println(e); 311 retval = 0; 312 } 313 314 if(retval == 0) { 315 System.out.print("\n"); 316 for(i = 0; i < h; i++) { 317 for(j = 0; j < w; j++) { 318 int r = buf[pitch * i + j * ps + roffset]; 319 int g = buf[pitch * i + j * ps + goffset]; 320 int b = buf[pitch * i + j * ps + boffset]; 321 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256; 322 System.out.format("%3d/%3d/%3d ", r, g, b); 323 } 324 System.out.print("\n"); 325 } 326 } 327 return retval; 328 } 329 330 private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf, 331 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception { 332 int rshift = TJ.getRedShift(pf); 333 int gshift = TJ.getGreenShift(pf); 334 int bshift = TJ.getBlueShift(pf); 335 int i, _i, j, retval = 1; 336 int halfway = 16 * scaleNum / scaleDenom; 337 int blockSize = 8 * scaleNum / scaleDenom; 338 339 try { 340 for(_i = 0; _i < halfway; _i++) { 341 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 342 else i = _i; 343 for(j = 0; j < w; j++) { 344 int r = (buf[pitch * i + j] >> rshift) & 0xFF; 345 int g = (buf[pitch * i + j] >> gshift) & 0xFF; 346 int b = (buf[pitch * i + j] >> bshift) & 0xFF; 347 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) { 348 checkVal255(_i, j, r, "R"); 349 checkVal255(_i, j, g, "G"); 350 checkVal255(_i, j, b, "B"); 351 } 352 else { 353 if(subsamp == TJ.SAMP_GRAY) { 354 checkVal(_i, j, r, "R", 76); 355 checkVal(_i, j, g, "G", 76); 356 checkVal(_i, j, b, "B", 76); 357 } 358 else { 359 checkVal255(_i, j, r, "R"); 360 checkVal0(_i, j, g, "G"); 361 checkVal0(_i, j, b, "B"); 362 } 363 } 364 } 365 } 366 for(_i = halfway; _i < h; _i++) { 367 if((flags & TJ.BOTTOMUP) != 0) i = h - _i - 1; 368 else i = _i; 369 for(j = 0; j < w; j++) { 370 int r = (buf[pitch * i + j] >> rshift) & 0xFF; 371 int g = (buf[pitch * i + j] >> gshift) & 0xFF; 372 int b = (buf[pitch * i + j] >> bshift) & 0xFF; 373 if(((_i / blockSize) + (j / blockSize)) % 2 == 0) { 374 checkVal0(_i, j, r, "R"); 375 checkVal0(_i, j, g, "G"); 376 } 377 else { 378 if(subsamp == TJ.SAMP_GRAY) { 379 checkVal(_i, j, r, "R", 226); 380 checkVal(_i, j, g, "G", 226); 381 checkVal(_i, j, b, "B", 226); 382 } 383 else { 384 checkVal255(_i, j, r, "R"); 385 checkVal255(_i, j, g, "G"); 386 checkVal0(_i, j, b, "B"); 387 } 388 } 389 } 390 } 391 } 392 catch(Exception e) { 393 System.out.println(e); 394 retval = 0; 395 } 396 397 if(retval == 0) { 398 System.out.print("\n"); 399 for(i = 0; i < h; i++) { 400 for(j = 0; j < w; j++) { 401 int r = (buf[pitch * i + j] >> rshift) & 0xFF; 402 int g = (buf[pitch * i + j] >> gshift) & 0xFF; 403 int b = (buf[pitch * i + j] >> bshift) & 0xFF; 404 if(r < 0) r += 256; if(g < 0) g += 256; if(b < 0) b += 256; 405 System.out.format("%3d/%3d/%3d ", r, g, b); 406 } 407 System.out.print("\n"); 408 } 409 } 410 return retval; 411 } 412 413 private static int checkImg(BufferedImage img, int pf, 414 int subsamp, int scaleNum, int scaleDenom, int flags) throws Exception { 415 WritableRaster wr = img.getRaster(); 416 int imgtype = img.getType(); 417 if(imgtype == BufferedImage.TYPE_INT_RGB 418 || imgtype == BufferedImage.TYPE_INT_BGR) { 419 SinglePixelPackedSampleModel sm = 420 (SinglePixelPackedSampleModel)img.getSampleModel(); 421 int pitch = sm.getScanlineStride(); 422 DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); 423 int[] buf = db.getData(); 424 return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, 425 subsamp, scaleNum, scaleDenom, flags); 426 } 427 else { 428 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel(); 429 int pitch = sm.getScanlineStride(); 430 DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); 431 byte[] buf = db.getData(); 432 return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp, 433 scaleNum, scaleDenom, flags); 434 } 435 } 436 437 private static int PAD(int v, int p) { 438 return ((v + (p) - 1) & (~((p) - 1))); 439 } 440 441 private static int checkBufYUV(byte[] buf, int size, int w, int h, 442 int subsamp) { 443 int i, j; 444 int hsf = horizSampFactor[subsamp], vsf = vertSampFactor[subsamp]; 445 int pw = PAD(w, hsf), ph = PAD(h, vsf); 446 int cw = pw / hsf, ch = ph / vsf; 447 int ypitch = PAD(pw, 4), uvpitch = PAD(cw, 4); 448 int retval = 1; 449 int correctsize = ypitch * ph 450 + (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2); 451 452 try { 453 if(size != correctsize) 454 throw new Exception("\nIncorrect size " + size + ". Should be " 455 + correctsize); 456 457 for(i = 0; i < 16; i++) { 458 for(j = 0; j < pw; j++) { 459 byte y = buf[ypitch * i + j]; 460 if(((i / 8) + (j / 8)) % 2 == 0) checkVal255(i, j, y, "Y"); 461 else checkVal(i, j, y, "Y", 76); 462 } 463 } 464 for(i = 16; i < ph; i++) { 465 for(j = 0; j < pw; j++) { 466 byte y = buf[ypitch * i + j]; 467 if(((i / 8) + (j / 8)) % 2 == 0) checkVal0(i, j, y, "Y"); 468 else checkVal(i, j, y, "Y", 226); 469 } 470 } 471 if(subsamp != TJ.SAMP_GRAY) { 472 for(i = 0; i < 16 / vsf; i++) { 473 for(j = 0; j < cw; j++) { 474 byte u = buf[ypitch * ph + (uvpitch * i + j)], 475 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)]; 476 if(((i * vsf / 8) + (j * hsf / 8)) % 2 == 0) { 477 checkVal(i, j, u, "U", 128); checkVal(i, j, v, "V", 128); 478 } 479 else { 480 checkVal(i, j, u, "U", 85); checkVal255(i, j, v, "V"); 481 } 482 } 483 } 484 for(i = 16 / vsf; i < ch; i++) { 485 for(j = 0; j < cw; j++) { 486 byte u = buf[ypitch * ph + (uvpitch * i + j)], 487 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)]; 488 if(((i * vsf / 8) + (j * hsf / 8)) % 2 == 0) { 489 checkVal(i, j, u, "U", 128); checkVal(i, j, v, "V", 128); 490 } 491 else { 492 checkVal0(i, j, u, "U"); checkVal(i, j, v, "V", 149); 493 } 494 } 495 } 496 } 497 } 498 catch(Exception e) { 499 System.out.println(e); 500 retval = 0; 501 } 502 503 if(retval == 0) { 504 for(i = 0; i < ph; i++) { 505 for(j = 0; j < pw; j++) { 506 int y = buf[ypitch * i + j]; 507 if(y < 0) y += 256; 508 System.out.format("%3d ", y); 509 } 510 System.out.print("\n"); 511 } 512 System.out.print("\n"); 513 for(i = 0; i < ch; i++) { 514 for(j = 0; j < cw; j++) { 515 int u = buf[ypitch * ph + (uvpitch * i + j)]; 516 if(u < 0) u += 256; 517 System.out.format("%3d ", u); 518 } 519 System.out.print("\n"); 520 } 521 System.out.print("\n"); 522 for(i = 0; i < ch; i++) { 523 for(j = 0; j < cw; j++) { 524 int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * i + j)]; 525 if(v < 0) v += 256; 526 System.out.format("%3d ", v); 527 } 528 System.out.print("\n"); 529 } 530 System.out.print("\n"); 531 } 532 533 return retval; 534 } 535 536 private static void writeJPEG(byte[] jpegBuf, int jpegBufSize, 537 String filename) throws Exception { 538 File file = new File(filename); 539 FileOutputStream fos = new FileOutputStream(file); 540 fos.write(jpegBuf, 0, jpegBufSize); 541 fos.close(); 542 } 543 544 private static int genTestJPEG(TJCompressor tjc, byte[] jpegBuf, int w, 545 int h, int pf, String baseFilename, int subsamp, int qual, 546 int flags) throws Exception { 547 String tempstr; 548 byte[] bmpBuf = null; 549 BufferedImage img = null; 550 String pfStr; 551 double t; 552 int size = 0, ps = TJ.getPixelSize(pf); 553 554 pfStr = pixFormatStr[pf]; 555 556 System.out.print(pfStr + " "); 557 if((flags & TJ.BOTTOMUP) != 0) System.out.print("Bottom-Up"); 558 else System.out.print("Top-Down "); 559 System.out.print(" -> " + subNameLong[subsamp] + " "); 560 if(yuv == YUVENCODE) System.out.print("YUV ... "); 561 else System.out.print("Q" + qual + " ... "); 562 563 if(bi) { 564 img = new BufferedImage(w, h, biType[pf]); 565 initImg(img, pf, flags); 566 tempstr = baseFilename + "_enc_" + pfStr + "_" 567 + (((flags & TJ.BOTTOMUP) != 0) ? "BU" : "TD") + "_" 568 + subName[subsamp] + "_Q" + qual + ".png"; 569 File file = new File(tempstr); 570 ImageIO.write(img, "png", file); 571 } 572 else { 573 bmpBuf = new byte[w * h * ps + 1]; 574 initBuf(bmpBuf, w, w * ps, h, pf, flags); 575 } 576 Arrays.fill(jpegBuf, (byte)0); 577 578 t = getTime(); 579 tjc.setSubsamp(subsamp); 580 tjc.setJPEGQuality(qual); 581 if(bi) { 582 if(yuv == YUVENCODE) tjc.encodeYUV(img, jpegBuf, flags); 583 else tjc.compress(img, jpegBuf, flags); 584 } 585 else { 586 tjc.setBitmapBuffer(bmpBuf, w, 0, h, pf); 587 if(yuv == YUVENCODE) tjc.encodeYUV(jpegBuf, flags); 588 else tjc.compress(jpegBuf, flags); 589 } 590 size = tjc.getCompressedSize(); 591 t = getTime() - t; 592 593 if(yuv == YUVENCODE) 594 tempstr = baseFilename + "_enc_" + pfStr + "_" 595 + (((flags & TJ.BOTTOMUP) != 0) ? "BU" : "TD") + "_" 596 + subName[subsamp] + ".yuv"; 597 else 598 tempstr = baseFilename + "_enc_" + pfStr + "_" 599 + (((flags & TJ.BOTTOMUP) != 0) ? "BU" : "TD") + "_" 600 + subName[subsamp] + "_Q" + qual + ".jpg"; 601 writeJPEG(jpegBuf, size, tempstr); 602 603 if(yuv == YUVENCODE) { 604 if(checkBufYUV(jpegBuf, size, w, h, subsamp) == 1) 605 System.out.print("Passed."); 606 else { 607 System.out.print("FAILED!"); exitStatus = -1; 608 } 609 } 610 else System.out.print("Done."); 611 System.out.format(" %.6f ms\n", t * 1000.); 612 System.out.println(" Result in " + tempstr); 613 614 return size; 615 } 616 617 private static void genTestBMP(TJDecompressor tjd, byte[] jpegBuf, 618 int jpegsize, int w, int h, int pf, String baseFilename, int subsamp, 619 int flags, int scaleNum, int scaleDenom) throws Exception { 620 String pfStr, tempstr; 621 double t; 622 int scaledWidth = (w * scaleNum + scaleDenom - 1) / scaleDenom; 623 int scaledHeight = (h * scaleNum + scaleDenom - 1) / scaleDenom; 624 int temp1, temp2; 625 BufferedImage img = null; 626 byte[] bmpBuf = null; 627 628 if(yuv == YUVENCODE) return; 629 630 pfStr = pixFormatStr[pf]; 631 System.out.print("JPEG -> "); 632 if(yuv == YUVDECODE) 633 System.out.print("YUV " + subName[subsamp] + " ... "); 634 else { 635 System.out.print(pfStr + " "); 636 if((flags & TJ.BOTTOMUP) != 0) System.out.print("Bottom-Up "); 637 else System.out.print("Top-Down "); 638 if(scaleNum != 1 || scaleDenom != 1) 639 System.out.print(scaleNum + "/" + scaleDenom + " ... "); 640 else System.out.print("... "); 641 } 642 643 t = getTime(); 644 tjd.setJPEGBuffer(jpegBuf, jpegsize); 645 if(tjd.getWidth() != w || tjd.getHeight() != h 646 || tjd.getSubsamp() != subsamp) 647 throw new Exception("Incorrect JPEG header"); 648 649 temp1 = scaledWidth; 650 temp2 = scaledHeight; 651 temp1 = tjd.getScaledWidth(temp1, temp2); 652 temp2 = tjd.getScaledHeight(temp1, temp2); 653 if(temp1 != scaledWidth || temp2 != scaledHeight) 654 throw new Exception("Scaled size mismatch"); 655 656 if(yuv == YUVDECODE) bmpBuf = tjd.decompressToYUV(flags); 657 else { 658 if(bi) 659 img = tjd.decompress(scaledWidth, scaledHeight, biType[pf], flags); 660 else bmpBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags); 661 } 662 t = getTime() - t; 663 664 if(bi) { 665 tempstr = baseFilename + "_dec_" + pfStr + "_" 666 + (((flags & TJ.BOTTOMUP) != 0) ? "BU" : "TD") + "_" 667 + subName[subsamp] + "_" + (double)scaleNum / (double)scaleDenom 668 + "x" + ".png"; 669 File file = new File(tempstr); 670 ImageIO.write(img, "png", file); 671 } 672 673 if(yuv == YUVDECODE) { 674 if(checkBufYUV(bmpBuf, bmpBuf.length, w, h, subsamp) == 1) 675 System.out.print("Passed."); 676 else { 677 System.out.print("FAILED!"); exitStatus = -1; 678 } 679 } 680 else { 681 if((bi && checkImg(img, pf, subsamp, scaleNum, scaleDenom, flags) == 1) 682 || (!bi && checkBuf(bmpBuf, scaledWidth, scaledWidth 683 * TJ.getPixelSize(pf), scaledHeight, pf, subsamp, scaleNum, 684 scaleDenom, flags) == 1)) 685 System.out.print("Passed."); 686 else { 687 System.out.print("FAILED!"); exitStatus = -1; 688 } 689 } 690 System.out.format(" %.6f ms\n", t * 1000.); 691 } 692 693 private static void genTestBMP(TJDecompressor tjd, byte[] jpegBuf, 694 int jpegsize, int w, int h, int pf, String baseFilename, int subsamp, 695 int flags) throws Exception { 696 int i; 697 if((subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY) && yuv == 0) { 698 TJ.ScalingFactor sf[] = TJ.getScalingFactors(); 699 for(i = 0; i < sf.length; i++) 700 genTestBMP(tjd, jpegBuf, jpegsize, w, h, pf, baseFilename, subsamp, 701 flags, sf[i].num, sf[i].denom); 702 } 703 else 704 genTestBMP(tjd, jpegBuf, jpegsize, w, h, pf, baseFilename, subsamp, 705 flags, 1, 1); 706 System.out.print("\n"); 707 } 708 709 private static void doTest(int w, int h, int[] formats, int subsamp, 710 String baseFilename) throws Exception { 711 TJCompressor tjc = null; 712 TJDecompressor tjd = null; 713 int size, pfstart, pfend; 714 byte[] jpegBuf; 715 716 if(yuv == YUVENCODE) jpegBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)]; 717 else jpegBuf = new byte[TJ.bufSize(w, h)]; 718 719 try { 720 tjc = new TJCompressor(); 721 tjd = new TJDecompressor(); 722 723 for(int pf : formats) { 724 for(int i = 0; i < 2; i++) { 725 int flags = 0; 726 if(i == 1) { 727 if(yuv == YUVDECODE) { 728 tjc.close(); tjd.close(); return; 729 } 730 else flags |= TJ.BOTTOMUP; 731 } 732 size = genTestJPEG(tjc, jpegBuf, w, h, pf, baseFilename, subsamp, 733 100, flags); 734 genTestBMP(tjd, jpegBuf, size, w, h, pf, baseFilename, subsamp, 735 flags); 736 } 737 } 738 } 739 catch(Exception e) { 740 if(tjc != null) tjc.close(); 741 if(tjd != null) tjd.close(); 742 throw e; 743 } 744 if(tjc != null) tjc.close(); 745 if(tjd != null) tjd.close(); 746 } 747 748 private final static int MAXLENGTH = 2048; 749 750 private static void doTest1() throws Exception { 751 int i, j, i2; 752 byte[] bmpBuf, jpegBuf; 753 TJCompressor tjc = null; 754 755 try { 756 tjc = new TJCompressor(); 757 System.out.println("Buffer size regression test"); 758 for(j = 1; j < 48; j++) { 759 for(i = 1; i < (j == 1 ? MAXLENGTH : 48); i++) { 760 if(i % 100 == 0) 761 System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", i, j); 762 bmpBuf = new byte[i * j * 4]; 763 jpegBuf = new byte[TJ.bufSize(i, j)]; 764 Arrays.fill(bmpBuf, (byte)0); 765 for(i2 = 0; i2 < i * j; i2++) { 766 bmpBuf[i2 * 4] = pixels[i2 % 9][2]; 767 bmpBuf[i2 * 4 + 1] = pixels[i2 % 9][1]; 768 bmpBuf[i2 * 4 + 2] = pixels[i2 % 9][0]; 769 } 770 tjc.setBitmapBuffer(bmpBuf, i, 0, j, TJ.PF_BGRX); 771 tjc.setSubsamp(TJ.SAMP_444); 772 tjc.setJPEGQuality(100); 773 tjc.compress(jpegBuf, 0); 774 775 bmpBuf = new byte[j * i * 4]; 776 jpegBuf = new byte[TJ.bufSize(j, i)]; 777 for(i2 = 0; i2 < j * i; i2++) { 778 if(i2 % 2 == 0) bmpBuf[i2 * 4] = 779 bmpBuf[i2 * 4 + 1] = bmpBuf[i2 * 4 + 2] = (byte)0xFF; 780 else bmpBuf[i2 * 4] = bmpBuf[i2 * 4 + 1] = bmpBuf[i2 * 4 + 2] = 0; 781 } 782 tjc.setBitmapBuffer(bmpBuf, j, 0, i, TJ.PF_BGRX); 783 tjc.compress(jpegBuf, 0); 784 } 785 } 786 System.out.println("Done. "); 787 } 788 catch(Exception e) { 789 if(tjc != null) tjc.close(); 790 throw e; 791 } 792 if(tjc != null) tjc.close(); 793 } 794 795 public static void main(String argv[]) { 796 try { 797 boolean doyuv = false; 798 for(int i = 0; i < argv.length; i++) { 799 if(argv[i].equalsIgnoreCase("-yuv")) doyuv = true; 800 if(argv[i].substring(0, 1).equalsIgnoreCase("-h") 801 || argv[i].equalsIgnoreCase("-?")) 802 usage(); 803 if(argv[i].equalsIgnoreCase("-bi")) bi = true; 804 } 805 if(doyuv) yuv = YUVENCODE; 806 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444, "test"); 807 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444, "test"); 808 if(doyuv) { 809 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422, 810 "test"); 811 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422, 812 "test"); 813 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420, 814 "test"); 815 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420, 816 "test"); 817 } 818 doTest(35, 39, onlyGray, TJ.SAMP_GRAY, "test"); 819 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY, 820 "test"); 821 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY, 822 "test"); 823 if(!doyuv && !bi) doTest1(); 824 if(doyuv && !bi) { 825 yuv = YUVDECODE; 826 doTest(48, 48, onlyRGB, TJ.SAMP_444, "test"); 827 doTest(35, 39, onlyRGB, TJ.SAMP_444, "test"); 828 doTest(48, 48, onlyRGB, TJ.SAMP_422, "test"); 829 doTest(39, 41, onlyRGB, TJ.SAMP_422, "test"); 830 doTest(48, 48, onlyRGB, TJ.SAMP_420, "test"); 831 doTest(41, 35, onlyRGB, TJ.SAMP_420, "test"); 832 doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "test"); 833 doTest(35, 39, onlyRGB, TJ.SAMP_GRAY, "test"); 834 doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "test"); 835 doTest(39, 41, onlyGray, TJ.SAMP_GRAY, "test"); 836 } 837 } 838 catch(Exception e) { 839 e.printStackTrace(); 840 exitStatus = -1; 841 } 842 System.exit(exitStatus); 843 } 844} 845