OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C)2011-2016 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 |
| 33 import java.io.*; |
| 34 import java.util.*; |
| 35 import java.awt.image.*; |
| 36 import javax.imageio.*; |
| 37 import java.nio.*; |
| 38 import org.libjpegturbo.turbojpeg.*; |
| 39 |
| 40 public 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("-noyuvpad = do not pad each line of each Y, U, and V pla
ne to the nearest\n"); |
| 50 System.out.println(" 4-byte boundary\n"); |
| 51 System.out.println("-bi = test BufferedImage support\n"); |
| 52 System.exit(1); |
| 53 } |
| 54 |
| 55 private static final String[] subNameLong = { |
| 56 "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1" |
| 57 }; |
| 58 private static final String[] subName = { |
| 59 "444", "422", "420", "GRAY", "440", "411" |
| 60 }; |
| 61 |
| 62 private static final String[] pixFormatStr = { |
| 63 "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "Grayscale", |
| 64 "RGBA", "BGRA", "ABGR", "ARGB", "CMYK" |
| 65 }; |
| 66 |
| 67 private static final int[] alphaOffset = { |
| 68 -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1 |
| 69 }; |
| 70 |
| 71 private static final int[] _3byteFormats = { |
| 72 TJ.PF_RGB, TJ.PF_BGR |
| 73 }; |
| 74 private static final int[] _3byteFormatsBI = { |
| 75 BufferedImage.TYPE_3BYTE_BGR |
| 76 }; |
| 77 private static final int[] _4byteFormats = { |
| 78 TJ.PF_RGBX, TJ.PF_BGRX, TJ.PF_XBGR, TJ.PF_XRGB, TJ.PF_CMYK |
| 79 }; |
| 80 private static final int[] _4byteFormatsBI = { |
| 81 BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_INT_RGB, |
| 82 BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_4BYTE_ABGR_PRE, |
| 83 BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_INT_ARGB_PRE |
| 84 }; |
| 85 private static final int[] onlyGray = { |
| 86 TJ.PF_GRAY |
| 87 }; |
| 88 private static final int[] onlyGrayBI = { |
| 89 BufferedImage.TYPE_BYTE_GRAY |
| 90 }; |
| 91 private static final int[] onlyRGB = { |
| 92 TJ.PF_RGB |
| 93 }; |
| 94 |
| 95 private static boolean doYUV = false; |
| 96 private static int pad = 4; |
| 97 private static boolean bi = false; |
| 98 |
| 99 private static int exitStatus = 0; |
| 100 |
| 101 private static int biTypePF(int biType) { |
| 102 ByteOrder byteOrder = ByteOrder.nativeOrder(); |
| 103 switch(biType) { |
| 104 case BufferedImage.TYPE_3BYTE_BGR: |
| 105 return TJ.PF_BGR; |
| 106 case BufferedImage.TYPE_4BYTE_ABGR: |
| 107 case BufferedImage.TYPE_4BYTE_ABGR_PRE: |
| 108 return TJ.PF_ABGR; |
| 109 case BufferedImage.TYPE_BYTE_GRAY: |
| 110 return TJ.PF_GRAY; |
| 111 case BufferedImage.TYPE_INT_BGR: |
| 112 if (byteOrder == ByteOrder.BIG_ENDIAN) |
| 113 return TJ.PF_XBGR; |
| 114 else |
| 115 return TJ.PF_RGBX; |
| 116 case BufferedImage.TYPE_INT_RGB: |
| 117 if (byteOrder == ByteOrder.BIG_ENDIAN) |
| 118 return TJ.PF_XRGB; |
| 119 else |
| 120 return TJ.PF_BGRX; |
| 121 case BufferedImage.TYPE_INT_ARGB: |
| 122 case BufferedImage.TYPE_INT_ARGB_PRE: |
| 123 if (byteOrder == ByteOrder.BIG_ENDIAN) |
| 124 return TJ.PF_ARGB; |
| 125 else |
| 126 return TJ.PF_BGRA; |
| 127 } |
| 128 return 0; |
| 129 } |
| 130 |
| 131 private static String biTypeStr(int biType) { |
| 132 switch(biType) { |
| 133 case BufferedImage.TYPE_3BYTE_BGR: |
| 134 return "3BYTE_BGR"; |
| 135 case BufferedImage.TYPE_4BYTE_ABGR: |
| 136 return "4BYTE_ABGR"; |
| 137 case BufferedImage.TYPE_4BYTE_ABGR_PRE: |
| 138 return "4BYTE_ABGR_PRE"; |
| 139 case BufferedImage.TYPE_BYTE_GRAY: |
| 140 return "BYTE_GRAY"; |
| 141 case BufferedImage.TYPE_INT_BGR: |
| 142 return "INT_BGR"; |
| 143 case BufferedImage.TYPE_INT_RGB: |
| 144 return "INT_RGB"; |
| 145 case BufferedImage.TYPE_INT_ARGB: |
| 146 return "INT_ARGB"; |
| 147 case BufferedImage.TYPE_INT_ARGB_PRE: |
| 148 return "INT_ARGB_PRE"; |
| 149 } |
| 150 return "Unknown"; |
| 151 } |
| 152 |
| 153 private static void initBuf(byte[] buf, int w, int pitch, int h, int pf, |
| 154 int flags) throws Exception { |
| 155 int roffset = TJ.getRedOffset(pf); |
| 156 int goffset = TJ.getGreenOffset(pf); |
| 157 int boffset = TJ.getBlueOffset(pf); |
| 158 int aoffset = alphaOffset[pf]; |
| 159 int ps = TJ.getPixelSize(pf); |
| 160 int index, row, col, halfway = 16; |
| 161 |
| 162 if (pf == TJ.PF_GRAY) { |
| 163 Arrays.fill(buf, (byte)0); |
| 164 for (row = 0; row < h; row++) { |
| 165 for (col = 0; col < w; col++) { |
| 166 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 167 index = pitch * (h - row - 1) + col; |
| 168 else |
| 169 index = pitch * row + col; |
| 170 if (((row / 8) + (col / 8)) % 2 == 0) |
| 171 buf[index] = (row < halfway) ? (byte)255 : 0; |
| 172 else |
| 173 buf[index] = (row < halfway) ? 76 : (byte)226; |
| 174 } |
| 175 } |
| 176 return; |
| 177 } |
| 178 if (pf == TJ.PF_CMYK) { |
| 179 Arrays.fill(buf, (byte)255); |
| 180 for (row = 0; row < h; row++) { |
| 181 for (col = 0; col < w; col++) { |
| 182 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 183 index = (h - row - 1) * w + col; |
| 184 else |
| 185 index = row * w + col; |
| 186 if (((row / 8) + (col / 8)) % 2 == 0) { |
| 187 if (row >= halfway) buf[index * ps + 3] = 0; |
| 188 } else { |
| 189 buf[index * ps + 2] = 0; |
| 190 if (row < halfway) |
| 191 buf[index * ps + 1] = 0; |
| 192 } |
| 193 } |
| 194 } |
| 195 return; |
| 196 } |
| 197 |
| 198 Arrays.fill(buf, (byte)0); |
| 199 for (row = 0; row < h; row++) { |
| 200 for (col = 0; col < w; col++) { |
| 201 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 202 index = pitch * (h - row - 1) + col * ps; |
| 203 else |
| 204 index = pitch * row + col * ps; |
| 205 if (((row / 8) + (col / 8)) % 2 == 0) { |
| 206 if (row < halfway) { |
| 207 buf[index + roffset] = (byte)255; |
| 208 buf[index + goffset] = (byte)255; |
| 209 buf[index + boffset] = (byte)255; |
| 210 } |
| 211 } else { |
| 212 buf[index + roffset] = (byte)255; |
| 213 if (row >= halfway) |
| 214 buf[index + goffset] = (byte)255; |
| 215 } |
| 216 if (aoffset >= 0) |
| 217 buf[index + aoffset] = (byte)255; |
| 218 } |
| 219 } |
| 220 } |
| 221 |
| 222 private static void initIntBuf(int[] buf, int w, int pitch, int h, int pf, |
| 223 int flags) throws Exception { |
| 224 int rshift = TJ.getRedOffset(pf) * 8; |
| 225 int gshift = TJ.getGreenOffset(pf) * 8; |
| 226 int bshift = TJ.getBlueOffset(pf) * 8; |
| 227 int ashift = alphaOffset[pf] * 8; |
| 228 int index, row, col, halfway = 16; |
| 229 |
| 230 Arrays.fill(buf, 0); |
| 231 for (row = 0; row < h; row++) { |
| 232 for (col = 0; col < w; col++) { |
| 233 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 234 index = pitch * (h - row - 1) + col; |
| 235 else |
| 236 index = pitch * row + col; |
| 237 if (((row / 8) + (col / 8)) % 2 == 0) { |
| 238 if (row < halfway) { |
| 239 buf[index] |= (255 << rshift); |
| 240 buf[index] |= (255 << gshift); |
| 241 buf[index] |= (255 << bshift); |
| 242 } |
| 243 } else { |
| 244 buf[index] |= (255 << rshift); |
| 245 if (row >= halfway) |
| 246 buf[index] |= (255 << gshift); |
| 247 } |
| 248 if (ashift >= 0) |
| 249 buf[index] |= (255 << ashift); |
| 250 } |
| 251 } |
| 252 } |
| 253 |
| 254 private static void initImg(BufferedImage img, int pf, int flags) |
| 255 throws Exception { |
| 256 WritableRaster wr = img.getRaster(); |
| 257 int imgType = img.getType(); |
| 258 if (imgType == BufferedImage.TYPE_INT_RGB || |
| 259 imgType == BufferedImage.TYPE_INT_BGR || |
| 260 imgType == BufferedImage.TYPE_INT_ARGB || |
| 261 imgType == BufferedImage.TYPE_INT_ARGB_PRE) { |
| 262 SinglePixelPackedSampleModel sm = |
| 263 (SinglePixelPackedSampleModel)img.getSampleModel(); |
| 264 int pitch = sm.getScanlineStride(); |
| 265 DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); |
| 266 int[] buf = db.getData(); |
| 267 initIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags); |
| 268 } else { |
| 269 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel(); |
| 270 int pitch = sm.getScanlineStride(); |
| 271 DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); |
| 272 byte[] buf = db.getData(); |
| 273 initBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, flags); |
| 274 } |
| 275 } |
| 276 |
| 277 private static void checkVal(int row, int col, int v, String vname, int cv) |
| 278 throws Exception { |
| 279 v = (v < 0) ? v + 256 : v; |
| 280 if (v < cv - 1 || v > cv + 1) { |
| 281 throw new Exception("Comp. " + vname + " at " + row + "," + col + |
| 282 " should be " + cv + ", not " + v); |
| 283 } |
| 284 } |
| 285 |
| 286 private static void checkVal0(int row, int col, int v, String vname) |
| 287 throws Exception { |
| 288 v = (v < 0) ? v + 256 : v; |
| 289 if (v > 1) { |
| 290 throw new Exception("Comp. " + vname + " at " + row + "," + col + |
| 291 " should be 0, not " + v); |
| 292 } |
| 293 } |
| 294 |
| 295 private static void checkVal255(int row, int col, int v, String vname) |
| 296 throws Exception { |
| 297 v = (v < 0) ? v + 256 : v; |
| 298 if (v < 254) { |
| 299 throw new Exception("Comp. " + vname + " at " + row + "," + col + |
| 300 " should be 255, not " + v); |
| 301 } |
| 302 } |
| 303 |
| 304 private static int checkBuf(byte[] buf, int w, int pitch, int h, int pf, |
| 305 int subsamp, TJScalingFactor sf, int flags) |
| 306 throws Exception { |
| 307 int roffset = TJ.getRedOffset(pf); |
| 308 int goffset = TJ.getGreenOffset(pf); |
| 309 int boffset = TJ.getBlueOffset(pf); |
| 310 int aoffset = alphaOffset[pf]; |
| 311 int ps = TJ.getPixelSize(pf); |
| 312 int index, row, col, retval = 1; |
| 313 int halfway = 16 * sf.getNum() / sf.getDenom(); |
| 314 int blockSize = 8 * sf.getNum() / sf.getDenom(); |
| 315 |
| 316 try { |
| 317 |
| 318 if (pf == TJ.PF_CMYK) { |
| 319 for (row = 0; row < h; row++) { |
| 320 for (col = 0; col < w; col++) { |
| 321 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 322 index = (h - row - 1) * w + col; |
| 323 else |
| 324 index = row * w + col; |
| 325 byte c = buf[index * ps]; |
| 326 byte m = buf[index * ps + 1]; |
| 327 byte y = buf[index * ps + 2]; |
| 328 byte k = buf[index * ps + 3]; |
| 329 checkVal255(row, col, c, "C"); |
| 330 if (((row / blockSize) + (col / blockSize)) % 2 == 0) { |
| 331 checkVal255(row, col, m, "M"); |
| 332 checkVal255(row, col, y, "Y"); |
| 333 if (row < halfway) |
| 334 checkVal255(row, col, k, "K"); |
| 335 else |
| 336 checkVal0(row, col, k, "K"); |
| 337 } else { |
| 338 checkVal0(row, col, y, "Y"); |
| 339 checkVal255(row, col, k, "K"); |
| 340 if (row < halfway) |
| 341 checkVal0(row, col, m, "M"); |
| 342 else |
| 343 checkVal255(row, col, m, "M"); |
| 344 } |
| 345 } |
| 346 } |
| 347 return 1; |
| 348 } |
| 349 |
| 350 for (row = 0; row < halfway; row++) { |
| 351 for (col = 0; col < w; col++) { |
| 352 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 353 index = pitch * (h - row - 1) + col * ps; |
| 354 else |
| 355 index = pitch * row + col * ps; |
| 356 byte r = buf[index + roffset]; |
| 357 byte g = buf[index + goffset]; |
| 358 byte b = buf[index + boffset]; |
| 359 byte a = aoffset >= 0 ? buf[index + aoffset] : (byte)255; |
| 360 if (((row / blockSize) + (col / blockSize)) % 2 == 0) { |
| 361 if (row < halfway) { |
| 362 checkVal255(row, col, r, "R"); |
| 363 checkVal255(row, col, g, "G"); |
| 364 checkVal255(row, col, b, "B"); |
| 365 } else { |
| 366 checkVal0(row, col, r, "R"); |
| 367 checkVal0(row, col, g, "G"); |
| 368 checkVal0(row, col, b, "B"); |
| 369 } |
| 370 } else { |
| 371 if (subsamp == TJ.SAMP_GRAY) { |
| 372 if (row < halfway) { |
| 373 checkVal(row, col, r, "R", 76); |
| 374 checkVal(row, col, g, "G", 76); |
| 375 checkVal(row, col, b, "B", 76); |
| 376 } else { |
| 377 checkVal(row, col, r, "R", 226); |
| 378 checkVal(row, col, g, "G", 226); |
| 379 checkVal(row, col, b, "B", 226); |
| 380 } |
| 381 } else { |
| 382 checkVal255(row, col, r, "R"); |
| 383 if (row < halfway) { |
| 384 checkVal0(row, col, g, "G"); |
| 385 } else { |
| 386 checkVal255(row, col, g, "G"); |
| 387 } |
| 388 checkVal0(row, col, b, "B"); |
| 389 } |
| 390 } |
| 391 checkVal255(row, col, a, "A"); |
| 392 } |
| 393 } |
| 394 } catch(Exception e) { |
| 395 System.out.println("\n" + e.getMessage()); |
| 396 retval = 0; |
| 397 } |
| 398 |
| 399 if (retval == 0) { |
| 400 for (row = 0; row < h; row++) { |
| 401 for (col = 0; col < w; col++) { |
| 402 if (pf == TJ.PF_CMYK) { |
| 403 int c = buf[pitch * row + col * ps]; |
| 404 int m = buf[pitch * row + col * ps + 1]; |
| 405 int y = buf[pitch * row + col * ps + 2]; |
| 406 int k = buf[pitch * row + col * ps + 3]; |
| 407 if (c < 0) c += 256; |
| 408 if (m < 0) m += 256; |
| 409 if (y < 0) y += 256; |
| 410 if (k < 0) k += 256; |
| 411 System.out.format("%3d/%3d/%3d/%3d ", c, m, y, k); |
| 412 } else { |
| 413 int r = buf[pitch * row + col * ps + roffset]; |
| 414 int g = buf[pitch * row + col * ps + goffset]; |
| 415 int b = buf[pitch * row + col * ps + boffset]; |
| 416 if (r < 0) r += 256; |
| 417 if (g < 0) g += 256; |
| 418 if (b < 0) b += 256; |
| 419 System.out.format("%3d/%3d/%3d ", r, g, b); |
| 420 } |
| 421 } |
| 422 System.out.print("\n"); |
| 423 } |
| 424 } |
| 425 return retval; |
| 426 } |
| 427 |
| 428 private static int checkIntBuf(int[] buf, int w, int pitch, int h, int pf, |
| 429 int subsamp, TJScalingFactor sf, int flags) |
| 430 throws Exception { |
| 431 int rshift = TJ.getRedOffset(pf) * 8; |
| 432 int gshift = TJ.getGreenOffset(pf) * 8; |
| 433 int bshift = TJ.getBlueOffset(pf) * 8; |
| 434 int ashift = alphaOffset[pf] * 8; |
| 435 int index, row, col, retval = 1; |
| 436 int halfway = 16 * sf.getNum() / sf.getDenom(); |
| 437 int blockSize = 8 * sf.getNum() / sf.getDenom(); |
| 438 |
| 439 try { |
| 440 for (row = 0; row < halfway; row++) { |
| 441 for (col = 0; col < w; col++) { |
| 442 if ((flags & TJ.FLAG_BOTTOMUP) != 0) |
| 443 index = pitch * (h - row - 1) + col; |
| 444 else |
| 445 index = pitch * row + col; |
| 446 int r = (buf[index] >> rshift) & 0xFF; |
| 447 int g = (buf[index] >> gshift) & 0xFF; |
| 448 int b = (buf[index] >> bshift) & 0xFF; |
| 449 int a = ashift >= 0 ? (buf[index] >> ashift) & 0xFF : 255; |
| 450 if (((row / blockSize) + (col / blockSize)) % 2 == 0) { |
| 451 if (row < halfway) { |
| 452 checkVal255(row, col, r, "R"); |
| 453 checkVal255(row, col, g, "G"); |
| 454 checkVal255(row, col, b, "B"); |
| 455 } else { |
| 456 checkVal0(row, col, r, "R"); |
| 457 checkVal0(row, col, g, "G"); |
| 458 checkVal0(row, col, b, "B"); |
| 459 } |
| 460 } else { |
| 461 if (subsamp == TJ.SAMP_GRAY) { |
| 462 if (row < halfway) { |
| 463 checkVal(row, col, r, "R", 76); |
| 464 checkVal(row, col, g, "G", 76); |
| 465 checkVal(row, col, b, "B", 76); |
| 466 } else { |
| 467 checkVal(row, col, r, "R", 226); |
| 468 checkVal(row, col, g, "G", 226); |
| 469 checkVal(row, col, b, "B", 226); |
| 470 } |
| 471 } else { |
| 472 checkVal255(row, col, r, "R"); |
| 473 if (row < halfway) { |
| 474 checkVal0(row, col, g, "G"); |
| 475 } else { |
| 476 checkVal255(row, col, g, "G"); |
| 477 } |
| 478 checkVal0(row, col, b, "B"); |
| 479 } |
| 480 } |
| 481 checkVal255(row, col, a, "A"); |
| 482 } |
| 483 } |
| 484 } catch(Exception e) { |
| 485 System.out.println("\n" + e.getMessage()); |
| 486 retval = 0; |
| 487 } |
| 488 |
| 489 if (retval == 0) { |
| 490 for (row = 0; row < h; row++) { |
| 491 for (col = 0; col < w; col++) { |
| 492 int r = (buf[pitch * row + col] >> rshift) & 0xFF; |
| 493 int g = (buf[pitch * row + col] >> gshift) & 0xFF; |
| 494 int b = (buf[pitch * row + col] >> bshift) & 0xFF; |
| 495 if (r < 0) r += 256; |
| 496 if (g < 0) g += 256; |
| 497 if (b < 0) b += 256; |
| 498 System.out.format("%3d/%3d/%3d ", r, g, b); |
| 499 } |
| 500 System.out.print("\n"); |
| 501 } |
| 502 } |
| 503 return retval; |
| 504 } |
| 505 |
| 506 private static int checkImg(BufferedImage img, int pf, int subsamp, |
| 507 TJScalingFactor sf, int flags) throws Exception { |
| 508 WritableRaster wr = img.getRaster(); |
| 509 int imgType = img.getType(); |
| 510 if (imgType == BufferedImage.TYPE_INT_RGB || |
| 511 imgType == BufferedImage.TYPE_INT_BGR || |
| 512 imgType == BufferedImage.TYPE_INT_ARGB || |
| 513 imgType == BufferedImage.TYPE_INT_ARGB_PRE) { |
| 514 SinglePixelPackedSampleModel sm = |
| 515 (SinglePixelPackedSampleModel)img.getSampleModel(); |
| 516 int pitch = sm.getScanlineStride(); |
| 517 DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); |
| 518 int[] buf = db.getData(); |
| 519 return checkIntBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, |
| 520 subsamp, sf, flags); |
| 521 } else { |
| 522 ComponentSampleModel sm = (ComponentSampleModel)img.getSampleModel(); |
| 523 int pitch = sm.getScanlineStride(); |
| 524 DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); |
| 525 byte[] buf = db.getData(); |
| 526 return checkBuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp, |
| 527 sf, flags); |
| 528 } |
| 529 } |
| 530 |
| 531 private static int PAD(int v, int p) { |
| 532 return ((v + (p) - 1) & (~((p) - 1))); |
| 533 } |
| 534 |
| 535 private static int checkBufYUV(byte[] buf, int size, int w, int h, |
| 536 int subsamp, TJScalingFactor sf) |
| 537 throws Exception { |
| 538 int row, col; |
| 539 int hsf = TJ.getMCUWidth(subsamp) / 8, vsf = TJ.getMCUHeight(subsamp) / 8; |
| 540 int pw = PAD(w, hsf), ph = PAD(h, vsf); |
| 541 int cw = pw / hsf, ch = ph / vsf; |
| 542 int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad); |
| 543 int retval = 1; |
| 544 int correctsize = ypitch * ph + |
| 545 (subsamp == TJ.SAMP_GRAY ? 0 : uvpitch * ch * 2); |
| 546 int halfway = 16 * sf.getNum() / sf.getDenom(); |
| 547 int blockSize = 8 * sf.getNum() / sf.getDenom(); |
| 548 |
| 549 try { |
| 550 if (size != correctsize) |
| 551 throw new Exception("Incorrect size " + size + ". Should be " + |
| 552 correctsize); |
| 553 |
| 554 for (row = 0; row < ph; row++) { |
| 555 for (col = 0; col < pw; col++) { |
| 556 byte y = buf[ypitch * row + col]; |
| 557 if (((row / blockSize) + (col / blockSize)) % 2 == 0) { |
| 558 if (row < halfway) |
| 559 checkVal255(row, col, y, "Y"); |
| 560 else |
| 561 checkVal0(row, col, y, "Y"); |
| 562 } else { |
| 563 if (row < halfway) |
| 564 checkVal(row, col, y, "Y", 76); |
| 565 else |
| 566 checkVal(row, col, y, "Y", 226); |
| 567 } |
| 568 } |
| 569 } |
| 570 if (subsamp != TJ.SAMP_GRAY) { |
| 571 halfway = 16 / vsf * sf.getNum() / sf.getDenom(); |
| 572 for (row = 0; row < ch; row++) { |
| 573 for (col = 0; col < cw; col++) { |
| 574 byte u = buf[ypitch * ph + (uvpitch * row + col)], |
| 575 v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]; |
| 576 if (((row * vsf / blockSize) + (col * hsf / blockSize)) % 2 == 0) { |
| 577 checkVal(row, col, u, "U", 128); |
| 578 checkVal(row, col, v, "V", 128); |
| 579 } else { |
| 580 if (row < halfway) { |
| 581 checkVal(row, col, u, "U", 85); |
| 582 checkVal255(row, col, v, "V"); |
| 583 } else { |
| 584 checkVal0(row, col, u, "U"); |
| 585 checkVal(row, col, v, "V", 149); |
| 586 } |
| 587 } |
| 588 } |
| 589 } |
| 590 } |
| 591 } catch(Exception e) { |
| 592 System.out.println("\n" + e.getMessage()); |
| 593 retval = 0; |
| 594 } |
| 595 |
| 596 if (retval == 0) { |
| 597 for (row = 0; row < ph; row++) { |
| 598 for (col = 0; col < pw; col++) { |
| 599 int y = buf[ypitch * row + col]; |
| 600 if (y < 0) y += 256; |
| 601 System.out.format("%3d ", y); |
| 602 } |
| 603 System.out.print("\n"); |
| 604 } |
| 605 System.out.print("\n"); |
| 606 for (row = 0; row < ch; row++) { |
| 607 for (col = 0; col < cw; col++) { |
| 608 int u = buf[ypitch * ph + (uvpitch * row + col)]; |
| 609 if (u < 0) u += 256; |
| 610 System.out.format("%3d ", u); |
| 611 } |
| 612 System.out.print("\n"); |
| 613 } |
| 614 System.out.print("\n"); |
| 615 for (row = 0; row < ch; row++) { |
| 616 for (col = 0; col < cw; col++) { |
| 617 int v = buf[ypitch * ph + uvpitch * ch + (uvpitch * row + col)]; |
| 618 if (v < 0) v += 256; |
| 619 System.out.format("%3d ", v); |
| 620 } |
| 621 System.out.print("\n"); |
| 622 } |
| 623 } |
| 624 |
| 625 return retval; |
| 626 } |
| 627 |
| 628 private static void writeJPEG(byte[] jpegBuf, int jpegBufSize, |
| 629 String filename) throws Exception { |
| 630 File file = new File(filename); |
| 631 FileOutputStream fos = new FileOutputStream(file); |
| 632 fos.write(jpegBuf, 0, jpegBufSize); |
| 633 fos.close(); |
| 634 } |
| 635 |
| 636 private static int compTest(TJCompressor tjc, byte[] dstBuf, int w, |
| 637 int h, int pf, String baseName, int subsamp, |
| 638 int jpegQual, int flags) throws Exception { |
| 639 String tempStr; |
| 640 byte[] srcBuf = null; |
| 641 BufferedImage img = null; |
| 642 String pfStr, pfStrLong; |
| 643 String buStr = (flags & TJ.FLAG_BOTTOMUP) != 0 ? "BU" : "TD"; |
| 644 String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ? |
| 645 "Bottom-Up" : "Top-Down "; |
| 646 int size = 0, ps, imgType = pf; |
| 647 |
| 648 if (bi) { |
| 649 pf = biTypePF(imgType); |
| 650 pfStr = biTypeStr(imgType); |
| 651 pfStrLong = pfStr + " (" + pixFormatStr[pf] + ")"; |
| 652 } else { |
| 653 pfStr = pixFormatStr[pf]; |
| 654 pfStrLong = pfStr; |
| 655 } |
| 656 ps = TJ.getPixelSize(pf); |
| 657 |
| 658 if (bi) { |
| 659 img = new BufferedImage(w, h, imgType); |
| 660 initImg(img, pf, flags); |
| 661 tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" + |
| 662 subName[subsamp] + "_Q" + jpegQual + ".png"; |
| 663 File file = new File(tempStr); |
| 664 ImageIO.write(img, "png", file); |
| 665 tjc.setSourceImage(img, 0, 0, 0, 0); |
| 666 } else { |
| 667 srcBuf = new byte[w * h * ps + 1]; |
| 668 initBuf(srcBuf, w, w * ps, h, pf, flags); |
| 669 tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, pf); |
| 670 } |
| 671 Arrays.fill(dstBuf, (byte)0); |
| 672 |
| 673 tjc.setSubsamp(subsamp); |
| 674 tjc.setJPEGQuality(jpegQual); |
| 675 if (doYUV) { |
| 676 System.out.format("%s %s -> YUV %s ... ", pfStrLong, buStrLong, |
| 677 subNameLong[subsamp]); |
| 678 YUVImage yuvImage = tjc.encodeYUV(pad, flags); |
| 679 if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), w, h, subsamp, |
| 680 new TJScalingFactor(1, 1)) == 1) |
| 681 System.out.print("Passed.\n"); |
| 682 else { |
| 683 System.out.print("FAILED!\n"); |
| 684 exitStatus = -1; |
| 685 } |
| 686 |
| 687 System.out.format("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp], |
| 688 buStrLong, jpegQual); |
| 689 tjc.setSourceImage(yuvImage); |
| 690 } else { |
| 691 System.out.format("%s %s -> %s Q%d ... ", pfStrLong, buStrLong, |
| 692 subNameLong[subsamp], jpegQual); |
| 693 } |
| 694 tjc.compress(dstBuf, flags); |
| 695 size = tjc.getCompressedSize(); |
| 696 |
| 697 tempStr = baseName + "_enc_" + pfStr + "_" + buStr + "_" + |
| 698 subName[subsamp] + "_Q" + jpegQual + ".jpg"; |
| 699 writeJPEG(dstBuf, size, tempStr); |
| 700 System.out.println("Done.\n Result in " + tempStr); |
| 701 |
| 702 return size; |
| 703 } |
| 704 |
| 705 private static void decompTest(TJDecompressor tjd, byte[] jpegBuf, |
| 706 int jpegSize, int w, int h, int pf, |
| 707 String baseName, int subsamp, int flags, |
| 708 TJScalingFactor sf) throws Exception { |
| 709 String pfStr, pfStrLong, tempStr; |
| 710 String buStrLong = (flags & TJ.FLAG_BOTTOMUP) != 0 ? |
| 711 "Bottom-Up" : "Top-Down "; |
| 712 int scaledWidth = sf.getScaled(w); |
| 713 int scaledHeight = sf.getScaled(h); |
| 714 int temp1, temp2, imgType = pf; |
| 715 BufferedImage img = null; |
| 716 byte[] dstBuf = null; |
| 717 |
| 718 if (bi) { |
| 719 pf = biTypePF(imgType); |
| 720 pfStr = biTypeStr(imgType); |
| 721 pfStrLong = pfStr + " (" + pixFormatStr[pf] + ")"; |
| 722 } else { |
| 723 pfStr = pixFormatStr[pf]; |
| 724 pfStrLong = pfStr; |
| 725 } |
| 726 |
| 727 tjd.setSourceImage(jpegBuf, jpegSize); |
| 728 if (tjd.getWidth() != w || tjd.getHeight() != h || |
| 729 tjd.getSubsamp() != subsamp) |
| 730 throw new Exception("Incorrect JPEG header"); |
| 731 |
| 732 temp1 = scaledWidth; |
| 733 temp2 = scaledHeight; |
| 734 temp1 = tjd.getScaledWidth(temp1, temp2); |
| 735 temp2 = tjd.getScaledHeight(temp1, temp2); |
| 736 if (temp1 != scaledWidth || temp2 != scaledHeight) |
| 737 throw new Exception("Scaled size mismatch"); |
| 738 |
| 739 if (doYUV) { |
| 740 System.out.format("JPEG -> YUV %s ", subNameLong[subsamp]); |
| 741 if(!sf.isOne()) |
| 742 System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom()); |
| 743 else System.out.print("... "); |
| 744 YUVImage yuvImage = tjd.decompressToYUV(scaledWidth, pad, scaledHeight, |
| 745 flags); |
| 746 if (checkBufYUV(yuvImage.getBuf(), yuvImage.getSize(), scaledWidth, |
| 747 scaledHeight, subsamp, sf) == 1) |
| 748 System.out.print("Passed.\n"); |
| 749 else { |
| 750 System.out.print("FAILED!\n"); exitStatus = -1; |
| 751 } |
| 752 |
| 753 System.out.format("YUV %s -> %s %s ... ", subNameLong[subsamp], |
| 754 pfStrLong, buStrLong); |
| 755 tjd.setSourceImage(yuvImage); |
| 756 } else { |
| 757 System.out.format("JPEG -> %s %s ", pfStrLong, buStrLong); |
| 758 if(!sf.isOne()) |
| 759 System.out.format("%d/%d ... ", sf.getNum(), sf.getDenom()); |
| 760 else System.out.print("... "); |
| 761 } |
| 762 if (bi) |
| 763 img = tjd.decompress(scaledWidth, scaledHeight, imgType, flags); |
| 764 else |
| 765 dstBuf = tjd.decompress(scaledWidth, 0, scaledHeight, pf, flags); |
| 766 |
| 767 if (bi) { |
| 768 tempStr = baseName + "_dec_" + pfStr + "_" + |
| 769 (((flags & TJ.FLAG_BOTTOMUP) != 0) ? "BU" : "TD") + "_" + |
| 770 subName[subsamp] + "_" + |
| 771 (double)sf.getNum() / (double)sf.getDenom() + "x" + ".png"; |
| 772 File file = new File(tempStr); |
| 773 ImageIO.write(img, "png", file); |
| 774 } |
| 775 |
| 776 if ((bi && checkImg(img, pf, subsamp, sf, flags) == 1) || |
| 777 (!bi && checkBuf(dstBuf, scaledWidth, |
| 778 scaledWidth * TJ.getPixelSize(pf), scaledHeight, pf, |
| 779 subsamp, sf, flags) == 1)) |
| 780 System.out.print("Passed.\n"); |
| 781 else { |
| 782 System.out.print("FAILED!\n"); |
| 783 exitStatus = -1; |
| 784 } |
| 785 } |
| 786 |
| 787 private static void decompTest(TJDecompressor tjd, byte[] jpegBuf, |
| 788 int jpegSize, int w, int h, int pf, |
| 789 String baseName, int subsamp, |
| 790 int flags) throws Exception { |
| 791 int i; |
| 792 TJScalingFactor[] sf = TJ.getScalingFactors(); |
| 793 for (i = 0; i < sf.length; i++) { |
| 794 int num = sf[i].getNum(); |
| 795 int denom = sf[i].getDenom(); |
| 796 if (subsamp == TJ.SAMP_444 || subsamp == TJ.SAMP_GRAY || |
| 797 (subsamp == TJ.SAMP_411 && num == 1 && |
| 798 (denom == 2 || denom == 1)) || |
| 799 (subsamp != TJ.SAMP_411 && num == 1 && |
| 800 (denom == 4 || denom == 2 || denom == 1))) |
| 801 decompTest(tjd, jpegBuf, jpegSize, w, h, pf, baseName, subsamp, |
| 802 flags, sf[i]); |
| 803 } |
| 804 } |
| 805 |
| 806 private static void doTest(int w, int h, int[] formats, int subsamp, |
| 807 String baseName) throws Exception { |
| 808 TJCompressor tjc = null; |
| 809 TJDecompressor tjd = null; |
| 810 int size; |
| 811 byte[] dstBuf; |
| 812 |
| 813 dstBuf = new byte[TJ.bufSize(w, h, subsamp)]; |
| 814 |
| 815 try { |
| 816 tjc = new TJCompressor(); |
| 817 tjd = new TJDecompressor(); |
| 818 |
| 819 for (int pf : formats) { |
| 820 if (pf < 0) continue; |
| 821 for (int i = 0; i < 2; i++) { |
| 822 int flags = 0; |
| 823 if (subsamp == TJ.SAMP_422 || subsamp == TJ.SAMP_420 || |
| 824 subsamp == TJ.SAMP_440 || subsamp == TJ.SAMP_411) |
| 825 flags |= TJ.FLAG_FASTUPSAMPLE; |
| 826 if (i == 1) |
| 827 flags |= TJ.FLAG_BOTTOMUP; |
| 828 size = compTest(tjc, dstBuf, w, h, pf, baseName, subsamp, 100, |
| 829 flags); |
| 830 decompTest(tjd, dstBuf, size, w, h, pf, baseName, subsamp, flags); |
| 831 if (pf >= TJ.PF_RGBX && pf <= TJ.PF_XRGB && !bi) { |
| 832 System.out.print("\n"); |
| 833 decompTest(tjd, dstBuf, size, w, h, pf + (TJ.PF_RGBA - TJ.PF_RGBX), |
| 834 baseName, subsamp, flags); |
| 835 } |
| 836 System.out.print("\n"); |
| 837 } |
| 838 } |
| 839 System.out.print("--------------------\n\n"); |
| 840 } catch(Exception e) { |
| 841 if (tjc != null) tjc.close(); |
| 842 if (tjd != null) tjd.close(); |
| 843 throw e; |
| 844 } |
| 845 if (tjc != null) tjc.close(); |
| 846 if (tjd != null) tjd.close(); |
| 847 } |
| 848 |
| 849 private static void bufSizeTest() throws Exception { |
| 850 int w, h, i, subsamp; |
| 851 byte[] srcBuf, dstBuf = null; |
| 852 YUVImage dstImage = null; |
| 853 TJCompressor tjc = null; |
| 854 Random r = new Random(); |
| 855 |
| 856 try { |
| 857 tjc = new TJCompressor(); |
| 858 System.out.println("Buffer size regression test"); |
| 859 for (subsamp = 0; subsamp < TJ.NUMSAMP; subsamp++) { |
| 860 for (w = 1; w < 48; w++) { |
| 861 int maxh = (w == 1) ? 2048 : 48; |
| 862 for (h = 1; h < maxh; h++) { |
| 863 if (h % 100 == 0) |
| 864 System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h); |
| 865 srcBuf = new byte[w * h * 4]; |
| 866 if (doYUV) |
| 867 dstImage = new YUVImage(w, pad, h, subsamp); |
| 868 else |
| 869 dstBuf = new byte[TJ.bufSize(w, h, subsamp)]; |
| 870 for (i = 0; i < w * h * 4; i++) { |
| 871 srcBuf[i] = (byte)(r.nextInt(2) * 255); |
| 872 } |
| 873 tjc.setSourceImage(srcBuf, 0, 0, w, 0, h, TJ.PF_BGRX); |
| 874 tjc.setSubsamp(subsamp); |
| 875 tjc.setJPEGQuality(100); |
| 876 if (doYUV) |
| 877 tjc.encodeYUV(dstImage, 0); |
| 878 else |
| 879 tjc.compress(dstBuf, 0); |
| 880 |
| 881 srcBuf = new byte[h * w * 4]; |
| 882 if (doYUV) |
| 883 dstImage = new YUVImage(h, pad, w, subsamp); |
| 884 else |
| 885 dstBuf = new byte[TJ.bufSize(h, w, subsamp)]; |
| 886 for (i = 0; i < h * w * 4; i++) { |
| 887 srcBuf[i] = (byte)(r.nextInt(2) * 255); |
| 888 } |
| 889 tjc.setSourceImage(srcBuf, 0, 0, h, 0, w, TJ.PF_BGRX); |
| 890 if (doYUV) |
| 891 tjc.encodeYUV(dstImage, 0); |
| 892 else |
| 893 tjc.compress(dstBuf, 0); |
| 894 } |
| 895 dstImage = null; |
| 896 dstBuf = null; |
| 897 System.gc(); |
| 898 } |
| 899 } |
| 900 System.out.println("Done. "); |
| 901 } catch(Exception e) { |
| 902 if (tjc != null) tjc.close(); |
| 903 throw e; |
| 904 } |
| 905 if (tjc != null) tjc.close(); |
| 906 } |
| 907 |
| 908 public static void main(String[] argv) { |
| 909 try { |
| 910 String testName = "javatest"; |
| 911 for (int i = 0; i < argv.length; i++) { |
| 912 if (argv[i].equalsIgnoreCase("-yuv")) |
| 913 doYUV = true; |
| 914 if (argv[i].equalsIgnoreCase("-noyuvpad")) |
| 915 pad = 1; |
| 916 if (argv[i].substring(0, 1).equalsIgnoreCase("-h") || |
| 917 argv[i].equalsIgnoreCase("-?")) |
| 918 usage(); |
| 919 if (argv[i].equalsIgnoreCase("-bi")) { |
| 920 bi = true; |
| 921 testName = "javabitest"; |
| 922 } |
| 923 } |
| 924 if (doYUV) |
| 925 _4byteFormats[4] = -1; |
| 926 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_444, |
| 927 testName); |
| 928 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_444, |
| 929 testName); |
| 930 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_422, |
| 931 testName); |
| 932 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_422, |
| 933 testName); |
| 934 doTest(39, 41, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_420, |
| 935 testName); |
| 936 doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_420, |
| 937 testName); |
| 938 doTest(35, 39, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_440, |
| 939 testName); |
| 940 doTest(39, 41, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_440, |
| 941 testName); |
| 942 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_411, |
| 943 testName); |
| 944 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_411, |
| 945 testName); |
| 946 doTest(39, 41, bi ? onlyGrayBI : onlyGray, TJ.SAMP_GRAY, testName); |
| 947 doTest(41, 35, bi ? _3byteFormatsBI : _3byteFormats, TJ.SAMP_GRAY, |
| 948 testName); |
| 949 _4byteFormats[4] = -1; |
| 950 doTest(35, 39, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY, |
| 951 testName); |
| 952 if (!bi) |
| 953 bufSizeTest(); |
| 954 if (doYUV && !bi) { |
| 955 System.out.print("\n--------------------\n\n"); |
| 956 doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0"); |
| 957 doTest(48, 48, onlyRGB, TJ.SAMP_422, "javatest_yuv0"); |
| 958 doTest(48, 48, onlyRGB, TJ.SAMP_420, "javatest_yuv0"); |
| 959 doTest(48, 48, onlyRGB, TJ.SAMP_440, "javatest_yuv0"); |
| 960 doTest(48, 48, onlyRGB, TJ.SAMP_411, "javatest_yuv0"); |
| 961 doTest(48, 48, onlyRGB, TJ.SAMP_GRAY, "javatest_yuv0"); |
| 962 doTest(48, 48, onlyGray, TJ.SAMP_GRAY, "javatest_yuv0"); |
| 963 } |
| 964 } catch(Exception e) { |
| 965 e.printStackTrace(); |
| 966 exitStatus = -1; |
| 967 } |
| 968 System.exit(exitStatus); |
| 969 } |
| 970 } |
OLD | NEW |