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