blob: 36c1a8f7841e1b0ac5d8c9657e6217eeedfddd83 [file] [log] [blame]
DRCf8e00552011-02-04 11:06:36 +00001/*
2 * Copyright (C)2011 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
34import java.io.*;
DRCf5467112011-09-20 05:02:19 +000035import java.awt.*;
DRC026f7ce2011-02-23 20:51:54 +000036import java.awt.image.*;
DRCf5467112011-09-20 05:02:19 +000037import java.nio.*;
DRC026f7ce2011-02-23 20:51:54 +000038import javax.imageio.*;
DRC16c70772011-03-07 09:59:08 +000039import javax.swing.*;
DRCc5a41992011-02-08 06:54:36 +000040import org.libjpegturbo.turbojpeg.*;
DRCf8e00552011-02-04 11:06:36 +000041
DRCf5467112011-09-20 05:02:19 +000042public class TJExample implements TJCustomFilter {
DRCf8e00552011-02-04 11:06:36 +000043
DRC026f7ce2011-02-23 20:51:54 +000044 public static final String classname = new TJExample().getClass().getName();
DRCf8e00552011-02-04 11:06:36 +000045
DRC5528b552011-03-01 20:43:47 +000046 private static void usage() throws Exception {
DRC026f7ce2011-02-23 20:51:54 +000047 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");
DRCe1303ef2011-02-16 03:26:48 +000051 System.out.println("Options:\n");
DRC5528b552011-03-01 20:43:47 +000052 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++) {
DRCb2f94152011-04-02 02:09:03 +000055 System.out.print(sf[i].getNum() + "/" + sf[i].getDenom());
DRC5528b552011-03-01 20:43:47 +000056 if(sf.length == 2 && i != sf.length - 1) System.out.print(" or ");
57 else if(sf.length > 2) {
58 if(i != sf.length - 1) System.out.print(", ");
59 if(i == sf.length - 2) System.out.print("or ");
60 }
61 }
62 System.out.println(")\n");
DRC026f7ce2011-02-23 20:51:54 +000063 System.out.println("-samp <444|422|420|gray> = If the output image is a JPEG file, this specifies");
64 System.out.println(" the level of chrominance subsampling to use when");
65 System.out.println(" recompressing it. Default is to use the same level");
66 System.out.println(" of subsampling as the input, if the input is a JPEG");
67 System.out.println(" file, or 4:4:4 otherwise.\n");
68 System.out.println("-q <1-100> = If the output image is a JPEG file, this specifies the JPEG");
69 System.out.println(" quality to use when recompressing it (default = 95).\n");
DRCe8573012011-03-04 10:13:59 +000070 System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
71 System.out.println(" If the input image is a JPEG file, perform the corresponding lossless");
72 System.out.println(" transform prior to decompression (these options are mutually exclusive)\n");
73 System.out.println("-grayscale = If the input image is a JPEG file, perform lossless grayscale");
74 System.out.println(" conversion prior to decompression (can be combined with the other");
75 System.out.println(" transforms above)\n");
76 System.out.println("-crop X,Y,WxH = If the input image is a JPEG file, perform lossless cropping");
77 System.out.println(" prior to decompression. X,Y specifies the upper left corner of the");
78 System.out.println(" cropping region, and WxH specifies its width and height. X,Y must be");
79 System.out.println(" evenly divible by the MCU block size (8x8 if the source image was");
80 System.out.println(" compressed using no subsampling or grayscale, or 16x8 for 4:2:2 or 16x16");
81 System.out.println(" for 4:2:0.)\n");
DRC16c70772011-03-07 09:59:08 +000082 System.out.println("-display = Display output image (Output file need not be specified in this");
83 System.out.println(" case.)\n");
DRCe1303ef2011-02-16 03:26:48 +000084 System.exit(1);
85 }
86
DRC026f7ce2011-02-23 20:51:54 +000087 private final static String sampName[] = {
DRC7d4b0012011-03-04 13:40:42 +000088 "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0"
DRC026f7ce2011-02-23 20:51:54 +000089 };
90
DRCf8e00552011-02-04 11:06:36 +000091 public static void main(String argv[]) {
92
DRCf7f3ea42011-03-01 20:03:32 +000093 BufferedImage img = null; byte[] bmpBuf = null;
DRCe8573012011-03-04 10:13:59 +000094 TJTransform xform = new TJTransform();
DRC026f7ce2011-02-23 20:51:54 +000095
DRCf8e00552011-02-04 11:06:36 +000096 try {
97
DRC5528b552011-03-01 20:43:47 +000098 sf = TJ.getScalingFactors();
99
DRC026f7ce2011-02-23 20:51:54 +0000100 if(argv.length < 2) {
DRCe1303ef2011-02-16 03:26:48 +0000101 usage();
102 }
103
DRCb2f94152011-04-02 02:09:03 +0000104 TJScalingFactor scaleFactor = new TJScalingFactor(1, 1);
DRC026f7ce2011-02-23 20:51:54 +0000105 String inFormat = "jpg", outFormat = "jpg";
106 int outSubsamp = -1, outQual = 95;
DRC16c70772011-03-07 09:59:08 +0000107 boolean display = false;
DRC026f7ce2011-02-23 20:51:54 +0000108
DRC16c70772011-03-07 09:59:08 +0000109 if(argv.length > 1) {
110 for(int i = 1; i < argv.length; i++) {
DRC026f7ce2011-02-23 20:51:54 +0000111 if(argv[i].length() < 2) continue;
112 if(argv[i].length() > 2
113 && argv[i].substring(0, 3).equalsIgnoreCase("-sc")) {
DRC5528b552011-03-01 20:43:47 +0000114 int match = 0;
DRC026f7ce2011-02-23 20:51:54 +0000115 if(i < argv.length - 1) {
DRCf7f3ea42011-03-01 20:03:32 +0000116 String[] scaleArg = argv[++i].split("/");
DRC5528b552011-03-01 20:43:47 +0000117 if(scaleArg.length == 2) {
DRCb2f94152011-04-02 02:09:03 +0000118 TJScalingFactor tempsf =
119 new TJScalingFactor(Integer.parseInt(scaleArg[0]),
120 Integer.parseInt(scaleArg[1]));
DRC5528b552011-03-01 20:43:47 +0000121 for(int j = 0; j < sf.length; j++) {
DRCb2f94152011-04-02 02:09:03 +0000122 if(tempsf.equals(sf[j])) {
123 scaleFactor = sf[j];
DRC5528b552011-03-01 20:43:47 +0000124 match = 1; break;
125 }
126 }
127 }
DRC026f7ce2011-02-23 20:51:54 +0000128 }
DRC5528b552011-03-01 20:43:47 +0000129 if(match != 1) usage();
DRC026f7ce2011-02-23 20:51:54 +0000130 }
DRC7d4b0012011-03-04 13:40:42 +0000131 if(argv[i].equalsIgnoreCase("-h") || argv[i].equalsIgnoreCase("-?"))
DRC026f7ce2011-02-23 20:51:54 +0000132 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")) outSubsamp = TJ.SAMP_444;
140 else if(argv[i].equals("422")) outSubsamp = TJ.SAMP_422;
141 else if(argv[i].equals("420")) outSubsamp = TJ.SAMP_420;
142 else usage();
143 }
144 else usage();
145 }
146 if(argv[i].substring(0, 2).equalsIgnoreCase("-q")) {
147 if(i < argv.length - 1) {
148 int qual = Integer.parseInt(argv[++i]);
149 if(qual >= 1 && qual <= 100) outQual = qual;
150 else usage();
151 }
152 else usage();
DRCe1303ef2011-02-16 03:26:48 +0000153 }
DRCe8573012011-03-04 10:13:59 +0000154 if(argv[i].substring(0, 2).equalsIgnoreCase("-g"))
DRC92549de2011-03-15 20:52:02 +0000155 xform.options |= TJTransform.OPT_GRAY;
DRCe8573012011-03-04 10:13:59 +0000156 if(argv[i].equalsIgnoreCase("-hflip"))
DRC92549de2011-03-15 20:52:02 +0000157 xform.op = TJTransform.OP_HFLIP;
DRCe8573012011-03-04 10:13:59 +0000158 if(argv[i].equalsIgnoreCase("-vflip"))
DRC92549de2011-03-15 20:52:02 +0000159 xform.op = TJTransform.OP_VFLIP;
DRCe8573012011-03-04 10:13:59 +0000160 if(argv[i].equalsIgnoreCase("-transpose"))
DRC92549de2011-03-15 20:52:02 +0000161 xform.op = TJTransform.OP_TRANSPOSE;
DRCe8573012011-03-04 10:13:59 +0000162 if(argv[i].equalsIgnoreCase("-transverse"))
DRC92549de2011-03-15 20:52:02 +0000163 xform.op = TJTransform.OP_TRANSVERSE;
DRCe8573012011-03-04 10:13:59 +0000164 if(argv[i].equalsIgnoreCase("-rot90"))
DRC92549de2011-03-15 20:52:02 +0000165 xform.op = TJTransform.OP_ROT90;
DRCe8573012011-03-04 10:13:59 +0000166 if(argv[i].equalsIgnoreCase("-rot180"))
DRC92549de2011-03-15 20:52:02 +0000167 xform.op = TJTransform.OP_ROT180;
DRCe8573012011-03-04 10:13:59 +0000168 if(argv[i].equalsIgnoreCase("-rot270"))
DRC92549de2011-03-15 20:52:02 +0000169 xform.op = TJTransform.OP_ROT270;
DRCf5467112011-09-20 05:02:19 +0000170 if(argv[i].equalsIgnoreCase("-custom"))
171 xform.cf = new TJExample();
172 else if(argv[i].length() > 2
DRCe8573012011-03-04 10:13:59 +0000173 && argv[i].substring(0, 2).equalsIgnoreCase("-c")) {
174 if(i >= argv.length - 1) usage();
175 String[] cropArg = argv[++i].split(",");
176 if(cropArg.length != 3) usage();
177 String[] dimArg = cropArg[2].split("[xX]");
178 if(dimArg.length != 2) usage();
179 int tempx = Integer.parseInt(cropArg[0]);
180 int tempy = Integer.parseInt(cropArg[1]);
181 int tempw = Integer.parseInt(dimArg[0]);
182 int temph = Integer.parseInt(dimArg[1]);
DRC92549de2011-03-15 20:52:02 +0000183 if(tempx < 0 || tempy < 0 || tempw < 0 || temph < 0) usage();
DRCe8573012011-03-04 10:13:59 +0000184 xform.x = tempx; xform.y = tempy;
185 xform.width = tempw; xform.height = temph;
DRC92549de2011-03-15 20:52:02 +0000186 xform.options |= TJTransform.OPT_CROP;
DRCe8573012011-03-04 10:13:59 +0000187 }
DRC16c70772011-03-07 09:59:08 +0000188 if(argv[i].substring(0, 2).equalsIgnoreCase("-d"))
189 display = true;
DRCe1303ef2011-02-16 03:26:48 +0000190 }
DRCf8e00552011-02-04 11:06:36 +0000191 }
DRCf7f3ea42011-03-01 20:03:32 +0000192 String[] inFileTokens = argv[0].split("\\.");
DRC026f7ce2011-02-23 20:51:54 +0000193 if(inFileTokens.length > 1)
194 inFormat = inFileTokens[inFileTokens.length - 1];
DRC16c70772011-03-07 09:59:08 +0000195 String[] outFileTokens;
196 if(display) outFormat = "bmp";
197 else {
198 outFileTokens = argv[1].split("\\.");
199 if(outFileTokens.length > 1)
200 outFormat = outFileTokens[outFileTokens.length - 1];
201 }
DRCf8e00552011-02-04 11:06:36 +0000202
DRC026f7ce2011-02-23 20:51:54 +0000203 File file = new File(argv[0]);
DRC4f8c2952011-03-31 10:06:17 +0000204 int width, height;
DRC026f7ce2011-02-23 20:51:54 +0000205
206 if(inFormat.equalsIgnoreCase("jpg")) {
207 FileInputStream fis = new FileInputStream(file);
208 int inputSize = fis.available();
209 if(inputSize < 1) {
210 System.out.println("Input file contains no data");
211 System.exit(1);
212 }
DRCf7f3ea42011-03-01 20:03:32 +0000213 byte[] inputBuf = new byte[inputSize];
DRC026f7ce2011-02-23 20:51:54 +0000214 fis.read(inputBuf);
215 fis.close();
216
DRCe8573012011-03-04 10:13:59 +0000217 TJDecompressor tjd;
DRCf5467112011-09-20 05:02:19 +0000218 if(xform.op != TJTransform.OP_NONE || xform.options != 0
219 || xform.cf != null) {
DRCe8573012011-03-04 10:13:59 +0000220 TJTransformer tjt = new TJTransformer(inputBuf);
221 TJTransform t[] = new TJTransform[1];
222 t[0] = xform;
DRC92549de2011-03-15 20:52:02 +0000223 t[0].options |= TJTransform.OPT_TRIM;
DRCe8573012011-03-04 10:13:59 +0000224 TJDecompressor[] tjdx = tjt.transform(t, 0);
225 tjd = tjdx[0];
226 }
227 else tjd = new TJDecompressor(inputBuf);
228
DRC026f7ce2011-02-23 20:51:54 +0000229 width = tjd.getWidth();
230 height = tjd.getHeight();
231 int inSubsamp = tjd.getSubsamp();
232 System.out.println("Source Image: " + width + " x " + height
233 + " pixels, " + sampName[inSubsamp] + " subsampling");
234 if(outSubsamp < 0) outSubsamp = inSubsamp;
235
DRC92549de2011-03-15 20:52:02 +0000236 if(outFormat.equalsIgnoreCase("jpg")
237 && (xform.op != TJTransform.OP_NONE || xform.options != 0)
DRCb2f94152011-04-02 02:09:03 +0000238 && scaleFactor.isOne()) {
DRC7d4b0012011-03-04 13:40:42 +0000239 file = new File(argv[1]);
240 FileOutputStream fos = new FileOutputStream(file);
241 fos.write(tjd.getJPEGBuf(), 0, tjd.getJPEGSize());
242 fos.close();
243 System.exit(0);
244 }
245
DRCb2f94152011-04-02 02:09:03 +0000246 width = scaleFactor.getScaled(width);
247 height = scaleFactor.getScaled(height);
DRC026f7ce2011-02-23 20:51:54 +0000248
DRC4f1580c2011-02-25 06:11:03 +0000249 if(!outFormat.equalsIgnoreCase("jpg"))
250 img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB, 0);
DRC026f7ce2011-02-23 20:51:54 +0000251 else bmpBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, 0);
252 tjd.close();
DRCf8e00552011-02-04 11:06:36 +0000253 }
DRC026f7ce2011-02-23 20:51:54 +0000254 else {
255 img = ImageIO.read(file);
256 width = img.getWidth();
257 height = img.getHeight();
258 if(outSubsamp < 0) {
259 if(img.getType() == BufferedImage.TYPE_BYTE_GRAY)
260 outSubsamp = TJ.SAMP_GRAY;
261 else outSubsamp = TJ.SAMP_444;
262 }
DRCf8e00552011-02-04 11:06:36 +0000263 }
DRCe8573012011-03-04 10:13:59 +0000264 System.gc();
DRC16c70772011-03-07 09:59:08 +0000265 if(!display)
266 System.out.print("Dest. Image (" + outFormat + "): " + width + " x "
267 + height + " pixels");
DRCe1303ef2011-02-16 03:26:48 +0000268
DRC16c70772011-03-07 09:59:08 +0000269 if(display) {
270 ImageIcon icon = new ImageIcon(img);
271 JLabel label = new JLabel(icon, JLabel.CENTER);
272 JOptionPane.showMessageDialog(null, label, "Output Image",
273 JOptionPane.PLAIN_MESSAGE);
274 }
275 else if(outFormat.equalsIgnoreCase("jpg")) {
DRC026f7ce2011-02-23 20:51:54 +0000276 System.out.println(", " + sampName[outSubsamp]
277 + " subsampling, quality = " + outQual);
278 TJCompressor tjc = new TJCompressor();
279 int jpegSize;
DRCf7f3ea42011-03-01 20:03:32 +0000280 byte[] jpegBuf;
DRC026f7ce2011-02-23 20:51:54 +0000281
DRC4f1580c2011-02-25 06:11:03 +0000282 tjc.setSubsamp(outSubsamp);
283 tjc.setJPEGQuality(outQual);
DRC026f7ce2011-02-23 20:51:54 +0000284 if(img != null)
DRC4f1580c2011-02-25 06:11:03 +0000285 jpegBuf = tjc.compress(img, 0);
DRC026f7ce2011-02-23 20:51:54 +0000286 else {
DRC2c74e512011-03-16 00:02:53 +0000287 tjc.setSourceImage(bmpBuf, width, 0, height, TJ.PF_BGRX);
DRC4f1580c2011-02-25 06:11:03 +0000288 jpegBuf = tjc.compress(0);
DRC026f7ce2011-02-23 20:51:54 +0000289 }
DRC4f1580c2011-02-25 06:11:03 +0000290 jpegSize = tjc.getCompressedSize();
DRC026f7ce2011-02-23 20:51:54 +0000291 tjc.close();
292
293 file = new File(argv[1]);
294 FileOutputStream fos = new FileOutputStream(file);
295 fos.write(jpegBuf, 0, jpegSize);
296 fos.close();
DRCe1303ef2011-02-16 03:26:48 +0000297 }
DRC026f7ce2011-02-23 20:51:54 +0000298 else {
DRC0ad78a62011-02-23 20:57:17 +0000299 System.out.print("\n");
DRC026f7ce2011-02-23 20:51:54 +0000300 file = new File(argv[1]);
301 ImageIO.write(img, outFormat, file);
302 }
DRCf8e00552011-02-04 11:06:36 +0000303
DRCf7f3ea42011-03-01 20:03:32 +0000304 }
305 catch(Exception e) {
DRCe8573012011-03-04 10:13:59 +0000306 e.printStackTrace();
307 System.exit(-1);
DRCf8e00552011-02-04 11:06:36 +0000308 }
309 }
310
DRCf5467112011-09-20 05:02:19 +0000311 public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
312 Rectangle planeRegion, int componentIndex, int transformIndex,
313 TJTransform transform) throws Exception {
314 for(int i=0; i<bufferRegion.width*bufferRegion.height; i++) {
315 coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
316 }
317 }
318
DRCb2f94152011-04-02 02:09:03 +0000319 static TJScalingFactor sf [] = null;
DRCf8e00552011-02-04 11:06:36 +0000320};