TJExample.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (C)2011-2012, 2014-2015 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 demonstrates how to compress and decompress JPEG files using
  30. * the TurboJPEG JNI wrapper
  31. */
  32. import java.io.*;
  33. import java.awt.*;
  34. import java.awt.image.*;
  35. import java.nio.*;
  36. import javax.imageio.*;
  37. import javax.swing.*;
  38. import org.libjpegturbo.turbojpeg.*;
  39. public class TJExample implements TJCustomFilter {
  40. public static final String classname = new TJExample().getClass().getName();
  41. private static void usage() throws Exception {
  42. System.out.println("\nUSAGE: java " + classname + " <Input file> <Output file> [options]\n");
  43. System.out.println("Input and output files can be any image format that the Java Image I/O");
  44. System.out.println("extensions understand. If either filename ends in a .jpg extension, then");
  45. System.out.println("TurboJPEG will be used to compress or decompress the file.\n");
  46. System.out.println("Options:\n");
  47. System.out.println("-scale M/N = if the input image is a JPEG file, scale the width/height of the");
  48. System.out.print(" output image by a factor of M/N (M/N = ");
  49. for (int i = 0; i < sf.length; i++) {
  50. System.out.print(sf[i].getNum() + "/" + sf[i].getDenom());
  51. if (sf.length == 2 && i != sf.length - 1)
  52. System.out.print(" or ");
  53. else if (sf.length > 2) {
  54. if (i != sf.length - 1)
  55. System.out.print(", ");
  56. if (i == sf.length - 2)
  57. System.out.print("or ");
  58. }
  59. }
  60. System.out.println(")\n");
  61. System.out.println("-samp <444|422|420|gray> = If the output image is a JPEG file, this specifies");
  62. System.out.println(" the level of chrominance subsampling to use when");
  63. System.out.println(" recompressing it. Default is to use the same level");
  64. System.out.println(" of subsampling as the input, if the input is a JPEG");
  65. System.out.println(" file, or 4:4:4 otherwise.\n");
  66. System.out.println("-q <1-100> = If the output image is a JPEG file, this specifies the JPEG");
  67. System.out.println(" quality to use when recompressing it (default = 95).\n");
  68. System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
  69. System.out.println(" If the input image is a JPEG file, perform the corresponding lossless");
  70. System.out.println(" transform prior to decompression (these options are mutually exclusive)\n");
  71. System.out.println("-grayscale = If the input image is a JPEG file, perform lossless grayscale");
  72. System.out.println(" conversion prior to decompression (can be combined with the other");
  73. System.out.println(" transforms above)\n");
  74. System.out.println("-crop X,Y,WxH = If the input image is a JPEG file, perform lossless cropping");
  75. System.out.println(" prior to decompression. X,Y specifies the upper left corner of the");
  76. System.out.println(" cropping region, and WxH specifies its width and height. X,Y must be");
  77. System.out.println(" evenly divible by the MCU block size (8x8 if the source image was");
  78. System.out.println(" compressed using no subsampling or grayscale, or 16x8 for 4:2:2 or 16x16");
  79. System.out.println(" for 4:2:0.)\n");
  80. System.out.println("-display = Display output image (Output file need not be specified in this");
  81. System.out.println(" case.)\n");
  82. System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available in");
  83. System.out.println(" the underlying codec\n");
  84. System.out.println("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying");
  85. System.out.println(" codec\n");
  86. System.out.println("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the");
  87. System.out.println(" underlying codec\n");
  88. System.exit(1);
  89. }
  90. private static final String[] sampName = {
  91. "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0"
  92. };
  93. public static void main(String[] argv) {
  94. BufferedImage img = null;
  95. byte[] bmpBuf = null;
  96. TJTransform xform = new TJTransform();
  97. int flags = 0;
  98. try {
  99. sf = TJ.getScalingFactors();
  100. if (argv.length < 2) {
  101. usage();
  102. }
  103. TJScalingFactor scaleFactor = new TJScalingFactor(1, 1);
  104. String inFormat = "jpg", outFormat = "jpg";
  105. int outSubsamp = -1, outQual = 95;
  106. boolean display = false;
  107. if (argv.length > 1) {
  108. for (int i = 1; i < argv.length; i++) {
  109. if (argv[i].length() < 2)
  110. continue;
  111. if (argv[i].length() > 2 &&
  112. argv[i].substring(0, 3).equalsIgnoreCase("-sc")) {
  113. int match = 0;
  114. if (i < argv.length - 1) {
  115. String[] scaleArg = argv[++i].split("/");
  116. if (scaleArg.length == 2) {
  117. TJScalingFactor tempsf =
  118. new TJScalingFactor(Integer.parseInt(scaleArg[0]),
  119. Integer.parseInt(scaleArg[1]));
  120. for (int j = 0; j < sf.length; j++) {
  121. if (tempsf.equals(sf[j])) {
  122. scaleFactor = sf[j];
  123. match = 1;
  124. break;
  125. }
  126. }
  127. }
  128. }
  129. if (match != 1) usage();
  130. }
  131. if (argv[i].equalsIgnoreCase("-h") || argv[i].equalsIgnoreCase("-?"))
  132. usage();
  133. if (argv[i].length() > 2 &&
  134. argv[i].substring(0, 3).equalsIgnoreCase("-sa")) {
  135. if (i < argv.length - 1) {
  136. i++;
  137. if (argv[i].substring(0, 1).equalsIgnoreCase("g"))
  138. outSubsamp = TJ.SAMP_GRAY;
  139. else if (argv[i].equals("444"))
  140. outSubsamp = TJ.SAMP_444;
  141. else if (argv[i].equals("422"))
  142. outSubsamp = TJ.SAMP_422;
  143. else if (argv[i].equals("420"))
  144. outSubsamp = TJ.SAMP_420;
  145. else
  146. usage();
  147. } else
  148. usage();
  149. }
  150. if (argv[i].substring(0, 2).equalsIgnoreCase("-q")) {
  151. if (i < argv.length - 1) {
  152. int qual = Integer.parseInt(argv[++i]);
  153. if (qual >= 1 && qual <= 100)
  154. outQual = qual;
  155. else
  156. usage();
  157. } else
  158. usage();
  159. }
  160. if (argv[i].substring(0, 2).equalsIgnoreCase("-g"))
  161. xform.options |= TJTransform.OPT_GRAY;
  162. if (argv[i].equalsIgnoreCase("-hflip"))
  163. xform.op = TJTransform.OP_HFLIP;
  164. if (argv[i].equalsIgnoreCase("-vflip"))
  165. xform.op = TJTransform.OP_VFLIP;
  166. if (argv[i].equalsIgnoreCase("-transpose"))
  167. xform.op = TJTransform.OP_TRANSPOSE;
  168. if (argv[i].equalsIgnoreCase("-transverse"))
  169. xform.op = TJTransform.OP_TRANSVERSE;
  170. if (argv[i].equalsIgnoreCase("-rot90"))
  171. xform.op = TJTransform.OP_ROT90;
  172. if (argv[i].equalsIgnoreCase("-rot180"))
  173. xform.op = TJTransform.OP_ROT180;
  174. if (argv[i].equalsIgnoreCase("-rot270"))
  175. xform.op = TJTransform.OP_ROT270;
  176. if (argv[i].equalsIgnoreCase("-custom"))
  177. xform.cf = new TJExample();
  178. else if (argv[i].length() > 2 &&
  179. argv[i].substring(0, 2).equalsIgnoreCase("-c")) {
  180. if (i >= argv.length - 1)
  181. usage();
  182. String[] cropArg = argv[++i].split(",");
  183. if (cropArg.length != 3)
  184. usage();
  185. String[] dimArg = cropArg[2].split("[xX]");
  186. if (dimArg.length != 2)
  187. usage();
  188. int tempx = Integer.parseInt(cropArg[0]);
  189. int tempy = Integer.parseInt(cropArg[1]);
  190. int tempw = Integer.parseInt(dimArg[0]);
  191. int temph = Integer.parseInt(dimArg[1]);
  192. if (tempx < 0 || tempy < 0 || tempw < 0 || temph < 0)
  193. usage();
  194. xform.x = tempx;
  195. xform.y = tempy;
  196. xform.width = tempw;
  197. xform.height = temph;
  198. xform.options |= TJTransform.OPT_CROP;
  199. }
  200. if (argv[i].substring(0, 2).equalsIgnoreCase("-d"))
  201. display = true;
  202. if (argv[i].equalsIgnoreCase("-fastupsample")) {
  203. System.out.println("Using fast upsampling code");
  204. flags |= TJ.FLAG_FASTUPSAMPLE;
  205. }
  206. if (argv[i].equalsIgnoreCase("-fastdct")) {
  207. System.out.println("Using fastest DCT/IDCT algorithm");
  208. flags |= TJ.FLAG_FASTDCT;
  209. }
  210. if (argv[i].equalsIgnoreCase("-accuratedct")) {
  211. System.out.println("Using most accurate DCT/IDCT algorithm");
  212. flags |= TJ.FLAG_ACCURATEDCT;
  213. }
  214. }
  215. }
  216. String[] inFileTokens = argv[0].split("\\.");
  217. if (inFileTokens.length > 1)
  218. inFormat = inFileTokens[inFileTokens.length - 1];
  219. String[] outFileTokens;
  220. if (display)
  221. outFormat = "bmp";
  222. else {
  223. outFileTokens = argv[1].split("\\.");
  224. if (outFileTokens.length > 1)
  225. outFormat = outFileTokens[outFileTokens.length - 1];
  226. }
  227. File file = new File(argv[0]);
  228. int width, height;
  229. if (inFormat.equalsIgnoreCase("jpg")) {
  230. FileInputStream fis = new FileInputStream(file);
  231. int inputSize = fis.available();
  232. if (inputSize < 1) {
  233. System.out.println("Input file contains no data");
  234. System.exit(1);
  235. }
  236. byte[] inputBuf = new byte[inputSize];
  237. fis.read(inputBuf);
  238. fis.close();
  239. TJDecompressor tjd;
  240. if (xform.op != TJTransform.OP_NONE || xform.options != 0 ||
  241. xform.cf != null) {
  242. TJTransformer tjt = new TJTransformer(inputBuf);
  243. TJTransform[] t = new TJTransform[1];
  244. t[0] = xform;
  245. t[0].options |= TJTransform.OPT_TRIM;
  246. TJDecompressor[] tjdx = tjt.transform(t, 0);
  247. tjd = tjdx[0];
  248. } else
  249. tjd = new TJDecompressor(inputBuf);
  250. width = tjd.getWidth();
  251. height = tjd.getHeight();
  252. int inSubsamp = tjd.getSubsamp();
  253. System.out.println("Source Image: " + width + " x " + height +
  254. " pixels, " + sampName[inSubsamp] + " subsampling");
  255. if (outSubsamp < 0)
  256. outSubsamp = inSubsamp;
  257. if (outFormat.equalsIgnoreCase("jpg") &&
  258. (xform.op != TJTransform.OP_NONE || xform.options != 0) &&
  259. scaleFactor.isOne()) {
  260. file = new File(argv[1]);
  261. FileOutputStream fos = new FileOutputStream(file);
  262. fos.write(tjd.getJPEGBuf(), 0, tjd.getJPEGSize());
  263. fos.close();
  264. System.exit(0);
  265. }
  266. width = scaleFactor.getScaled(width);
  267. height = scaleFactor.getScaled(height);
  268. if (!outFormat.equalsIgnoreCase("jpg"))
  269. img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB,
  270. flags);
  271. else
  272. bmpBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, flags);
  273. tjd.close();
  274. } else {
  275. img = ImageIO.read(file);
  276. if (img == null)
  277. throw new Exception("Input image type not supported.");
  278. width = img.getWidth();
  279. height = img.getHeight();
  280. if (outSubsamp < 0) {
  281. if (img.getType() == BufferedImage.TYPE_BYTE_GRAY)
  282. outSubsamp = TJ.SAMP_GRAY;
  283. else
  284. outSubsamp = TJ.SAMP_444;
  285. }
  286. }
  287. System.gc();
  288. if (!display)
  289. System.out.print("Dest. Image (" + outFormat + "): " + width + " x " +
  290. height + " pixels");
  291. if (display) {
  292. ImageIcon icon = new ImageIcon(img);
  293. JLabel label = new JLabel(icon, JLabel.CENTER);
  294. JOptionPane.showMessageDialog(null, label, "Output Image",
  295. JOptionPane.PLAIN_MESSAGE);
  296. } else if (outFormat.equalsIgnoreCase("jpg")) {
  297. System.out.println(", " + sampName[outSubsamp] +
  298. " subsampling, quality = " + outQual);
  299. TJCompressor tjc = new TJCompressor();
  300. int jpegSize;
  301. byte[] jpegBuf;
  302. tjc.setSubsamp(outSubsamp);
  303. tjc.setJPEGQuality(outQual);
  304. if (img != null)
  305. tjc.setSourceImage(img, 0, 0, 0, 0);
  306. else {
  307. tjc.setSourceImage(bmpBuf, 0, 0, width, 0, height, TJ.PF_BGRX);
  308. }
  309. jpegBuf = tjc.compress(flags);
  310. jpegSize = tjc.getCompressedSize();
  311. tjc.close();
  312. file = new File(argv[1]);
  313. FileOutputStream fos = new FileOutputStream(file);
  314. fos.write(jpegBuf, 0, jpegSize);
  315. fos.close();
  316. } else {
  317. System.out.print("\n");
  318. file = new File(argv[1]);
  319. ImageIO.write(img, outFormat, file);
  320. }
  321. } catch(Exception e) {
  322. e.printStackTrace();
  323. System.exit(-1);
  324. }
  325. }
  326. public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
  327. Rectangle planeRegion, int componentIndex,
  328. int transformIndex, TJTransform transform)
  329. throws TJException {
  330. for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) {
  331. coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
  332. }
  333. }
  334. static TJScalingFactor[] sf = null;
  335. };