Home | History | Annotate | Download | only in java
      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 
     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 
    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 
    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