Home | History | Annotate | Download | only in java
      1 /*
      2  * Copyright (C)2011-2012, 2014 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 
     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 
    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 
    351   public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
    352                            Rectangle planeRegion, int componentIndex,
    353                            int transformIndex, TJTransform transform)
    354                            throws Exception {
    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