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