blob: 835a5b97375168638028e6e6abfed1afb4d1f8f6 [file] [log] [blame]
DRCf8e00552011-02-04 11:06:36 +00001/*
Leon Scroggins IIIbd7903e2018-02-28 14:05:04 -05002 * Copyright (C)2011-2012, 2014-2015, 2017 D. R. Commander.
3 * All Rights Reserved.
DRCf8e00552011-02-04 11:06:36 +00004 *
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
35import java.io.*;
DRCf5467112011-09-20 05:02:19 +000036import java.awt.*;
DRC026f7ce2011-02-23 20:51:54 +000037import java.awt.image.*;
DRCf5467112011-09-20 05:02:19 +000038import java.nio.*;
DRC026f7ce2011-02-23 20:51:54 +000039import javax.imageio.*;
DRC16c70772011-03-07 09:59:08 +000040import javax.swing.*;
DRCc5a41992011-02-08 06:54:36 +000041import org.libjpegturbo.turbojpeg.*;
DRCf8e00552011-02-04 11:06:36 +000042
DRCf5467112011-09-20 05:02:19 +000043public class TJExample implements TJCustomFilter {
DRCf8e00552011-02-04 11:06:36 +000044
DRC026f7ce2011-02-23 20:51:54 +000045 public static final String classname = new TJExample().getClass().getName();
DRCf8e00552011-02-04 11:06:36 +000046
DRC5528b552011-03-01 20:43:47 +000047 private static void usage() throws Exception {
DRC026f7ce2011-02-23 20:51:54 +000048 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");
DRCe1303ef2011-02-16 03:26:48 +000052 System.out.println("Options:\n");
DRC5528b552011-03-01 20:43:47 +000053 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 = ");
DRC67bee862013-04-27 12:36:07 +000055 for (int i = 0; i < sf.length; i++) {
DRCb2f94152011-04-02 02:09:03 +000056 System.out.print(sf[i].getNum() + "/" + sf[i].getDenom());
DRC67bee862013-04-27 12:36:07 +000057 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 ");
DRC5528b552011-03-01 20:43:47 +000064 }
65 }
66 System.out.println(")\n");
DRC026f7ce2011-02-23 20:51:54 +000067 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");
DRCe8573012011-03-04 10:13:59 +000074 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");
DRC16c70772011-03-07 09:59:08 +000086 System.out.println("-display = Display output image (Output file need not be specified in this");
87 System.out.println(" case.)\n");
DRC73d74c12012-06-29 23:46:38 +000088 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");
DRCe1303ef2011-02-16 03:26:48 +000094 System.exit(1);
95 }
96
DRC67bee862013-04-27 12:36:07 +000097 private static final String[] sampName = {
Leon Scroggins IIIbd7903e2018-02-28 14:05:04 -050098 "4:4:4", "4:2:2", "4:2:0", "Grayscale", "4:4:0", "4:1:1"
DRC026f7ce2011-02-23 20:51:54 +000099 };
100
DRC67bee862013-04-27 12:36:07 +0000101 public static void main(String[] argv) {
DRCf8e00552011-02-04 11:06:36 +0000102
DRC67bee862013-04-27 12:36:07 +0000103 BufferedImage img = null;
104 byte[] bmpBuf = null;
DRCe8573012011-03-04 10:13:59 +0000105 TJTransform xform = new TJTransform();
DRC73d74c12012-06-29 23:46:38 +0000106 int flags = 0;
DRC026f7ce2011-02-23 20:51:54 +0000107
DRCf8e00552011-02-04 11:06:36 +0000108 try {
109
DRC5528b552011-03-01 20:43:47 +0000110 sf = TJ.getScalingFactors();
111
DRC67bee862013-04-27 12:36:07 +0000112 if (argv.length < 2) {
DRCe1303ef2011-02-16 03:26:48 +0000113 usage();
114 }
115
DRCb2f94152011-04-02 02:09:03 +0000116 TJScalingFactor scaleFactor = new TJScalingFactor(1, 1);
DRC026f7ce2011-02-23 20:51:54 +0000117 String inFormat = "jpg", outFormat = "jpg";
118 int outSubsamp = -1, outQual = 95;
DRC16c70772011-03-07 09:59:08 +0000119 boolean display = false;
DRC026f7ce2011-02-23 20:51:54 +0000120
Leon Scroggins IIIbd7903e2018-02-28 14:05:04 -0500121 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;
DRC5528b552011-03-01 20:43:47 +0000141 }
142 }
DRC026f7ce2011-02-23 20:51:54 +0000143 }
DRC026f7ce2011-02-23 20:51:54 +0000144 }
Leon Scroggins IIIbd7903e2018-02-28 14:05:04 -0500145 if (match != 1) usage();
DRCe1303ef2011-02-16 03:26:48 +0000146 }
Leon Scroggins IIIbd7903e2018-02-28 14:05:04 -0500147 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();
DRCf8e00552011-02-04 11:06:36 +0000229 }
DRCf7f3ea42011-03-01 20:03:32 +0000230 String[] inFileTokens = argv[0].split("\\.");
DRC67bee862013-04-27 12:36:07 +0000231 if (inFileTokens.length > 1)
DRC026f7ce2011-02-23 20:51:54 +0000232 inFormat = inFileTokens[inFileTokens.length - 1];
DRC16c70772011-03-07 09:59:08 +0000233 String[] outFileTokens;
DRC67bee862013-04-27 12:36:07 +0000234 if (display)
235 outFormat = "bmp";
DRC16c70772011-03-07 09:59:08 +0000236 else {
237 outFileTokens = argv[1].split("\\.");
DRC67bee862013-04-27 12:36:07 +0000238 if (outFileTokens.length > 1)
DRC16c70772011-03-07 09:59:08 +0000239 outFormat = outFileTokens[outFileTokens.length - 1];
240 }
DRCf8e00552011-02-04 11:06:36 +0000241
DRC026f7ce2011-02-23 20:51:54 +0000242 File file = new File(argv[0]);
DRC4f8c2952011-03-31 10:06:17 +0000243 int width, height;
DRC026f7ce2011-02-23 20:51:54 +0000244
DRC67bee862013-04-27 12:36:07 +0000245 if (inFormat.equalsIgnoreCase("jpg")) {
DRC026f7ce2011-02-23 20:51:54 +0000246 FileInputStream fis = new FileInputStream(file);
247 int inputSize = fis.available();
DRC67bee862013-04-27 12:36:07 +0000248 if (inputSize < 1) {
DRC026f7ce2011-02-23 20:51:54 +0000249 System.out.println("Input file contains no data");
250 System.exit(1);
251 }
DRCf7f3ea42011-03-01 20:03:32 +0000252 byte[] inputBuf = new byte[inputSize];
DRC026f7ce2011-02-23 20:51:54 +0000253 fis.read(inputBuf);
254 fis.close();
255
DRCe8573012011-03-04 10:13:59 +0000256 TJDecompressor tjd;
DRC67bee862013-04-27 12:36:07 +0000257 if (xform.op != TJTransform.OP_NONE || xform.options != 0 ||
258 xform.cf != null) {
DRCe8573012011-03-04 10:13:59 +0000259 TJTransformer tjt = new TJTransformer(inputBuf);
DRC67bee862013-04-27 12:36:07 +0000260 TJTransform[] t = new TJTransform[1];
DRCe8573012011-03-04 10:13:59 +0000261 t[0] = xform;
DRC92549de2011-03-15 20:52:02 +0000262 t[0].options |= TJTransform.OPT_TRIM;
DRCe8573012011-03-04 10:13:59 +0000263 TJDecompressor[] tjdx = tjt.transform(t, 0);
264 tjd = tjdx[0];
DRC67bee862013-04-27 12:36:07 +0000265 } else
266 tjd = new TJDecompressor(inputBuf);
DRCe8573012011-03-04 10:13:59 +0000267
DRC026f7ce2011-02-23 20:51:54 +0000268 width = tjd.getWidth();
269 height = tjd.getHeight();
270 int inSubsamp = tjd.getSubsamp();
DRC67bee862013-04-27 12:36:07 +0000271 System.out.println("Source Image: " + width + " x " + height +
272 " pixels, " + sampName[inSubsamp] + " subsampling");
273 if (outSubsamp < 0)
274 outSubsamp = inSubsamp;
DRC026f7ce2011-02-23 20:51:54 +0000275
DRC67bee862013-04-27 12:36:07 +0000276 if (outFormat.equalsIgnoreCase("jpg") &&
277 (xform.op != TJTransform.OP_NONE || xform.options != 0) &&
278 scaleFactor.isOne()) {
DRC7d4b0012011-03-04 13:40:42 +0000279 file = new File(argv[1]);
280 FileOutputStream fos = new FileOutputStream(file);
DRC40dd3142014-08-17 12:23:49 +0000281 fos.write(tjd.getJPEGBuf(), 0, tjd.getJPEGSize());
DRC7d4b0012011-03-04 13:40:42 +0000282 fos.close();
283 System.exit(0);
284 }
285
DRCb2f94152011-04-02 02:09:03 +0000286 width = scaleFactor.getScaled(width);
287 height = scaleFactor.getScaled(height);
DRC026f7ce2011-02-23 20:51:54 +0000288
DRC67bee862013-04-27 12:36:07 +0000289 if (!outFormat.equalsIgnoreCase("jpg"))
DRC73d74c12012-06-29 23:46:38 +0000290 img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB,
291 flags);
DRC67bee862013-04-27 12:36:07 +0000292 else
293 bmpBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, flags);
DRC026f7ce2011-02-23 20:51:54 +0000294 tjd.close();
DRC67bee862013-04-27 12:36:07 +0000295 } else {
DRC026f7ce2011-02-23 20:51:54 +0000296 img = ImageIO.read(file);
DRC98ca1c32013-01-19 06:43:27 +0000297 if (img == null)
298 throw new Exception("Input image type not supported.");
DRC026f7ce2011-02-23 20:51:54 +0000299 width = img.getWidth();
300 height = img.getHeight();
DRC67bee862013-04-27 12:36:07 +0000301 if (outSubsamp < 0) {
302 if (img.getType() == BufferedImage.TYPE_BYTE_GRAY)
DRC026f7ce2011-02-23 20:51:54 +0000303 outSubsamp = TJ.SAMP_GRAY;
DRC67bee862013-04-27 12:36:07 +0000304 else
305 outSubsamp = TJ.SAMP_444;
DRC026f7ce2011-02-23 20:51:54 +0000306 }
DRCf8e00552011-02-04 11:06:36 +0000307 }
DRCe8573012011-03-04 10:13:59 +0000308 System.gc();
DRC67bee862013-04-27 12:36:07 +0000309 if (!display)
310 System.out.print("Dest. Image (" + outFormat + "): " + width + " x " +
311 height + " pixels");
DRCe1303ef2011-02-16 03:26:48 +0000312
DRC67bee862013-04-27 12:36:07 +0000313 if (display) {
DRC16c70772011-03-07 09:59:08 +0000314 ImageIcon icon = new ImageIcon(img);
315 JLabel label = new JLabel(icon, JLabel.CENTER);
316 JOptionPane.showMessageDialog(null, label, "Output Image",
DRC67bee862013-04-27 12:36:07 +0000317 JOptionPane.PLAIN_MESSAGE);
318 } else if (outFormat.equalsIgnoreCase("jpg")) {
319 System.out.println(", " + sampName[outSubsamp] +
320 " subsampling, quality = " + outQual);
DRC026f7ce2011-02-23 20:51:54 +0000321 TJCompressor tjc = new TJCompressor();
322 int jpegSize;
DRCf7f3ea42011-03-01 20:03:32 +0000323 byte[] jpegBuf;
DRC026f7ce2011-02-23 20:51:54 +0000324
DRC4f1580c2011-02-25 06:11:03 +0000325 tjc.setSubsamp(outSubsamp);
326 tjc.setJPEGQuality(outQual);
DRC67bee862013-04-27 12:36:07 +0000327 if (img != null)
DRCb1481392014-03-14 08:53:33 +0000328 tjc.setSourceImage(img, 0, 0, 0, 0);
DRC026f7ce2011-02-23 20:51:54 +0000329 else {
DRCb1481392014-03-14 08:53:33 +0000330 tjc.setSourceImage(bmpBuf, 0, 0, width, 0, height, TJ.PF_BGRX);
DRC026f7ce2011-02-23 20:51:54 +0000331 }
DRCb1481392014-03-14 08:53:33 +0000332 jpegBuf = tjc.compress(flags);
DRC4f1580c2011-02-25 06:11:03 +0000333 jpegSize = tjc.getCompressedSize();
DRC026f7ce2011-02-23 20:51:54 +0000334 tjc.close();
335
336 file = new File(argv[1]);
337 FileOutputStream fos = new FileOutputStream(file);
338 fos.write(jpegBuf, 0, jpegSize);
339 fos.close();
DRC67bee862013-04-27 12:36:07 +0000340 } else {
DRC0ad78a62011-02-23 20:57:17 +0000341 System.out.print("\n");
DRC026f7ce2011-02-23 20:51:54 +0000342 file = new File(argv[1]);
343 ImageIO.write(img, outFormat, file);
344 }
DRCf8e00552011-02-04 11:06:36 +0000345
DRC67bee862013-04-27 12:36:07 +0000346 } catch(Exception e) {
DRCe8573012011-03-04 10:13:59 +0000347 e.printStackTrace();
348 System.exit(-1);
DRCf8e00552011-02-04 11:06:36 +0000349 }
350 }
351
DRCf5467112011-09-20 05:02:19 +0000352 public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
DRC67bee862013-04-27 12:36:07 +0000353 Rectangle planeRegion, int componentIndex,
354 int transformIndex, TJTransform transform)
Alex Naidis6eb7d372016-10-16 23:10:08 +0200355 throws TJException {
DRC67bee862013-04-27 12:36:07 +0000356 for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++) {
357 coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
DRCf5467112011-09-20 05:02:19 +0000358 }
359 }
360
DRC67bee862013-04-27 12:36:07 +0000361 static TJScalingFactor[] sf = null;
DRCf8e00552011-02-04 11:06:36 +0000362};