TJUnitTest.java 33 KB

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