TJUnitTest.java 34 KB

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