blob: 4718db007fbfe0693d84037d8f6c117b239e5921 [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.*;
DRC026f7ce2011-02-23 20:51:54 +000035import java.awt.image.*;
36import javax.imageio.*;
DRCc5a41992011-02-08 06:54:36 +000037import org.libjpegturbo.turbojpeg.*;
DRCf8e00552011-02-04 11:06:36 +000038
DRC2413cb82011-02-08 02:11:37 +000039public class TJExample {
DRCf8e00552011-02-04 11:06:36 +000040
DRC026f7ce2011-02-23 20:51:54 +000041 public static final String classname = new TJExample().getClass().getName();
DRCf8e00552011-02-04 11:06:36 +000042
DRC5528b552011-03-01 20:43:47 +000043 private static void usage() throws Exception {
DRC026f7ce2011-02-23 20:51:54 +000044 System.out.println("\nUSAGE: java " + classname + " <Input file> <Output file> [options]\n");
45 System.out.println("Input and output files can be any image format that the Java Image I/O");
46 System.out.println("extensions understand. If either filename ends in a .jpg extension, then");
47 System.out.println("TurboJPEG will be used to compress or decompress the file.\n");
DRCe1303ef2011-02-16 03:26:48 +000048 System.out.println("Options:\n");
DRC5528b552011-03-01 20:43:47 +000049 System.out.println("-scale M/N = if the input image is a JPEG file, scale the width/height of the");
50 System.out.print(" output image by a factor of M/N (M/N = ");
51 for(int i = 0; i < sf.length; i++) {
52 System.out.print(sf[i].num + "/" + sf[i].denom);
53 if(sf.length == 2 && i != sf.length - 1) System.out.print(" or ");
54 else if(sf.length > 2) {
55 if(i != sf.length - 1) System.out.print(", ");
56 if(i == sf.length - 2) System.out.print("or ");
57 }
58 }
59 System.out.println(")\n");
DRC026f7ce2011-02-23 20:51:54 +000060 System.out.println("-samp <444|422|420|gray> = If the output image is a JPEG file, this specifies");
61 System.out.println(" the level of chrominance subsampling to use when");
62 System.out.println(" recompressing it. Default is to use the same level");
63 System.out.println(" of subsampling as the input, if the input is a JPEG");
64 System.out.println(" file, or 4:4:4 otherwise.\n");
65 System.out.println("-q <1-100> = If the output image is a JPEG file, this specifies the JPEG");
66 System.out.println(" quality to use when recompressing it (default = 95).\n");
DRCe8573012011-03-04 10:13:59 +000067 System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
68 System.out.println(" If the input image is a JPEG file, perform the corresponding lossless");
69 System.out.println(" transform prior to decompression (these options are mutually exclusive)\n");
70 System.out.println("-grayscale = If the input image is a JPEG file, perform lossless grayscale");
71 System.out.println(" conversion prior to decompression (can be combined with the other");
72 System.out.println(" transforms above)\n");
73 System.out.println("-crop X,Y,WxH = If the input image is a JPEG file, perform lossless cropping");
74 System.out.println(" prior to decompression. X,Y specifies the upper left corner of the");
75 System.out.println(" cropping region, and WxH specifies its width and height. X,Y must be");
76 System.out.println(" evenly divible by the MCU block size (8x8 if the source image was");
77 System.out.println(" compressed using no subsampling or grayscale, or 16x8 for 4:2:2 or 16x16");
78 System.out.println(" for 4:2:0.)\n");
DRCe1303ef2011-02-16 03:26:48 +000079 System.exit(1);
80 }
81
DRC026f7ce2011-02-23 20:51:54 +000082 private final static String sampName[] = {
83 "4:4:4", "4:2:2", "4:2:0", "Grayscale"
84 };
85
DRCf8e00552011-02-04 11:06:36 +000086 public static void main(String argv[]) {
87
DRCf7f3ea42011-03-01 20:03:32 +000088 BufferedImage img = null; byte[] bmpBuf = null;
DRCe8573012011-03-04 10:13:59 +000089 TJTransform xform = new TJTransform();
DRC026f7ce2011-02-23 20:51:54 +000090
DRCf8e00552011-02-04 11:06:36 +000091 try {
92
DRC5528b552011-03-01 20:43:47 +000093 sf = TJ.getScalingFactors();
94
DRC026f7ce2011-02-23 20:51:54 +000095 if(argv.length < 2) {
DRCe1303ef2011-02-16 03:26:48 +000096 usage();
97 }
98
DRC5528b552011-03-01 20:43:47 +000099 int scaleNum = 1, scaleDenom = 1;
DRC026f7ce2011-02-23 20:51:54 +0000100 String inFormat = "jpg", outFormat = "jpg";
101 int outSubsamp = -1, outQual = 95;
102
103 if(argv.length > 2) {
104 for(int i = 2; i < argv.length; i++) {
105 if(argv[i].length() < 2) continue;
106 if(argv[i].length() > 2
107 && argv[i].substring(0, 3).equalsIgnoreCase("-sc")) {
DRC5528b552011-03-01 20:43:47 +0000108 int match = 0;
DRC026f7ce2011-02-23 20:51:54 +0000109 if(i < argv.length - 1) {
DRC5528b552011-03-01 20:43:47 +0000110 int temp1 = 0, temp2 = 0;
DRCf7f3ea42011-03-01 20:03:32 +0000111 String[] scaleArg = argv[++i].split("/");
DRC5528b552011-03-01 20:43:47 +0000112 if(scaleArg.length == 2) {
113 temp1 = Integer.parseInt(scaleArg[0]);
114 temp2 = Integer.parseInt(scaleArg[1]);
115 for(int j = 0; j < sf.length; j++) {
116 if(temp1 == sf[j].num && temp2 == sf[j].denom) {
117 scaleNum = temp1; scaleDenom = temp2;
118 match = 1; break;
119 }
120 }
121 }
DRC026f7ce2011-02-23 20:51:54 +0000122 }
DRC5528b552011-03-01 20:43:47 +0000123 if(match != 1) usage();
DRC026f7ce2011-02-23 20:51:54 +0000124 }
125 if(argv[i].substring(0, 2).equalsIgnoreCase("-h")
126 || argv[i].equalsIgnoreCase("-?"))
127 usage();
128 if(argv[i].length() > 2
129 && argv[i].substring(0, 3).equalsIgnoreCase("-sa")) {
130 if(i < argv.length - 1) {
131 i++;
132 if(argv[i].substring(0, 1).equalsIgnoreCase("g"))
133 outSubsamp = TJ.SAMP_GRAY;
134 else if(argv[i].equals("444")) outSubsamp = TJ.SAMP_444;
135 else if(argv[i].equals("422")) outSubsamp = TJ.SAMP_422;
136 else if(argv[i].equals("420")) outSubsamp = TJ.SAMP_420;
137 else usage();
138 }
139 else usage();
140 }
141 if(argv[i].substring(0, 2).equalsIgnoreCase("-q")) {
142 if(i < argv.length - 1) {
143 int qual = Integer.parseInt(argv[++i]);
144 if(qual >= 1 && qual <= 100) outQual = qual;
145 else usage();
146 }
147 else usage();
DRCe1303ef2011-02-16 03:26:48 +0000148 }
DRCe8573012011-03-04 10:13:59 +0000149 if(argv[i].substring(0, 2).equalsIgnoreCase("-g"))
150 xform.options |= TJ.XFORM_GRAY;
151 if(argv[i].equalsIgnoreCase("-hflip"))
152 xform.op = TJ.XFORM_HFLIP;
153 if(argv[i].equalsIgnoreCase("-vflip"))
154 xform.op = TJ.XFORM_VFLIP;
155 if(argv[i].equalsIgnoreCase("-transpose"))
156 xform.op = TJ.XFORM_TRANSPOSE;
157 if(argv[i].equalsIgnoreCase("-transverse"))
158 xform.op = TJ.XFORM_TRANSVERSE;
159 if(argv[i].equalsIgnoreCase("-rot90"))
160 xform.op = TJ.XFORM_ROT90;
161 if(argv[i].equalsIgnoreCase("-rot180"))
162 xform.op = TJ.XFORM_ROT180;
163 if(argv[i].equalsIgnoreCase("-rot270"))
164 xform.op = TJ.XFORM_ROT270;
165 if(argv[i].length() > 2
166 && argv[i].substring(0, 2).equalsIgnoreCase("-c")) {
167 if(i >= argv.length - 1) usage();
168 String[] cropArg = argv[++i].split(",");
169 if(cropArg.length != 3) usage();
170 String[] dimArg = cropArg[2].split("[xX]");
171 if(dimArg.length != 2) usage();
172 int tempx = Integer.parseInt(cropArg[0]);
173 int tempy = Integer.parseInt(cropArg[1]);
174 int tempw = Integer.parseInt(dimArg[0]);
175 int temph = Integer.parseInt(dimArg[1]);
176 if(tempx < 0 || tempy < 0 || tempw < 1 || temph < 1) usage();
177 xform.x = tempx; xform.y = tempy;
178 xform.width = tempw; xform.height = temph;
179 xform.options |= TJ.XFORM_CROP;
180 }
DRCe1303ef2011-02-16 03:26:48 +0000181 }
DRCf8e00552011-02-04 11:06:36 +0000182 }
DRCf7f3ea42011-03-01 20:03:32 +0000183 String[] inFileTokens = argv[0].split("\\.");
DRC026f7ce2011-02-23 20:51:54 +0000184 if(inFileTokens.length > 1)
185 inFormat = inFileTokens[inFileTokens.length - 1];
DRCf7f3ea42011-03-01 20:03:32 +0000186 String[] outFileTokens = argv[1].split("\\.");
DRC026f7ce2011-02-23 20:51:54 +0000187 if(outFileTokens.length > 1)
188 outFormat = outFileTokens[outFileTokens.length - 1];
DRCf8e00552011-02-04 11:06:36 +0000189
DRC026f7ce2011-02-23 20:51:54 +0000190 File file = new File(argv[0]);
191 int width, height, subsamp = TJ.SAMP_444;
192
193 if(inFormat.equalsIgnoreCase("jpg")) {
194 FileInputStream fis = new FileInputStream(file);
195 int inputSize = fis.available();
196 if(inputSize < 1) {
197 System.out.println("Input file contains no data");
198 System.exit(1);
199 }
DRCf7f3ea42011-03-01 20:03:32 +0000200 byte[] inputBuf = new byte[inputSize];
DRC026f7ce2011-02-23 20:51:54 +0000201 fis.read(inputBuf);
202 fis.close();
203
DRCe8573012011-03-04 10:13:59 +0000204 TJDecompressor tjd;
205 TJ.ScalingFactor sf;
206 if(xform.op != TJ.XFORM_NONE || xform.options != 0) {
207 TJTransformer tjt = new TJTransformer(inputBuf);
208 TJTransform t[] = new TJTransform[1];
209 t[0] = xform;
210 t[0].options |= TJ.XFORM_TRIM;
211 TJDecompressor[] tjdx = tjt.transform(t, 0);
212 tjd = tjdx[0];
213 }
214 else tjd = new TJDecompressor(inputBuf);
215
DRC026f7ce2011-02-23 20:51:54 +0000216 width = tjd.getWidth();
217 height = tjd.getHeight();
218 int inSubsamp = tjd.getSubsamp();
219 System.out.println("Source Image: " + width + " x " + height
220 + " pixels, " + sampName[inSubsamp] + " subsampling");
221 if(outSubsamp < 0) outSubsamp = inSubsamp;
222
DRC5528b552011-03-01 20:43:47 +0000223 if(scaleNum != 1 || scaleDenom != 1) {
224 width = (width * scaleNum + scaleDenom - 1) / scaleDenom;
225 height = (height * scaleNum + scaleDenom - 1) / scaleDenom;
DRC026f7ce2011-02-23 20:51:54 +0000226 }
227
DRC4f1580c2011-02-25 06:11:03 +0000228 if(!outFormat.equalsIgnoreCase("jpg"))
229 img = tjd.decompress(width, height, BufferedImage.TYPE_INT_RGB, 0);
DRC026f7ce2011-02-23 20:51:54 +0000230 else bmpBuf = tjd.decompress(width, 0, height, TJ.PF_BGRX, 0);
231 tjd.close();
DRCf8e00552011-02-04 11:06:36 +0000232 }
DRC026f7ce2011-02-23 20:51:54 +0000233 else {
234 img = ImageIO.read(file);
235 width = img.getWidth();
236 height = img.getHeight();
237 if(outSubsamp < 0) {
238 if(img.getType() == BufferedImage.TYPE_BYTE_GRAY)
239 outSubsamp = TJ.SAMP_GRAY;
240 else outSubsamp = TJ.SAMP_444;
241 }
DRCf8e00552011-02-04 11:06:36 +0000242 }
DRCe8573012011-03-04 10:13:59 +0000243 System.gc();
DRC026f7ce2011-02-23 20:51:54 +0000244 System.out.print("Dest. Image (" + outFormat + "): " + width + " x "
245 + height + " pixels");
DRCe1303ef2011-02-16 03:26:48 +0000246
DRC026f7ce2011-02-23 20:51:54 +0000247 if(outFormat.equalsIgnoreCase("jpg")) {
248 System.out.println(", " + sampName[outSubsamp]
249 + " subsampling, quality = " + outQual);
250 TJCompressor tjc = new TJCompressor();
251 int jpegSize;
DRCf7f3ea42011-03-01 20:03:32 +0000252 byte[] jpegBuf;
DRC026f7ce2011-02-23 20:51:54 +0000253
DRC4f1580c2011-02-25 06:11:03 +0000254 tjc.setSubsamp(outSubsamp);
255 tjc.setJPEGQuality(outQual);
DRC026f7ce2011-02-23 20:51:54 +0000256 if(img != null)
DRC4f1580c2011-02-25 06:11:03 +0000257 jpegBuf = tjc.compress(img, 0);
DRC026f7ce2011-02-23 20:51:54 +0000258 else {
259 tjc.setBitmapBuffer(bmpBuf, width, 0, height, TJ.PF_BGRX);
DRC4f1580c2011-02-25 06:11:03 +0000260 jpegBuf = tjc.compress(0);
DRC026f7ce2011-02-23 20:51:54 +0000261 }
DRC4f1580c2011-02-25 06:11:03 +0000262 jpegSize = tjc.getCompressedSize();
DRC026f7ce2011-02-23 20:51:54 +0000263 tjc.close();
264
265 file = new File(argv[1]);
266 FileOutputStream fos = new FileOutputStream(file);
267 fos.write(jpegBuf, 0, jpegSize);
268 fos.close();
DRCe1303ef2011-02-16 03:26:48 +0000269 }
DRC026f7ce2011-02-23 20:51:54 +0000270 else {
DRC0ad78a62011-02-23 20:57:17 +0000271 System.out.print("\n");
DRC026f7ce2011-02-23 20:51:54 +0000272 file = new File(argv[1]);
273 ImageIO.write(img, outFormat, file);
274 }
DRCf8e00552011-02-04 11:06:36 +0000275
DRCf7f3ea42011-03-01 20:03:32 +0000276 }
277 catch(Exception e) {
DRCe8573012011-03-04 10:13:59 +0000278 e.printStackTrace();
279 System.exit(-1);
DRCf8e00552011-02-04 11:06:36 +0000280 }
281 }
282
DRC5528b552011-03-01 20:43:47 +0000283 static TJ.ScalingFactor sf [] = null;
DRCf8e00552011-02-04 11:06:36 +0000284};