Imported Upstream version 3.0.1
[platform/upstream/libjpeg-turbo.git] / java / TJBench.java
1 /*
2  * Copyright (C)2009-2014, 2016-2019, 2021-2023 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 import java.io.*;
31 import java.awt.*;
32 import java.awt.image.*;
33 import javax.imageio.*;
34 import java.nio.*;
35 import java.util.*;
36 import org.libjpegturbo.turbojpeg.*;
37
38 final class TJBench {
39
40   private TJBench() {}
41
42   private static boolean stopOnWarning, bottomUp, fastUpsample, fastDCT,
43     optimize, progressive, limitScans, arithmetic, lossless;
44   private static int precision = 8, quiet = 0, pf = TJ.PF_BGR, yuvAlign = 1,
45     restartIntervalBlocks, restartIntervalRows = 0;
46   private static boolean compOnly, decompOnly, doTile, doYUV, write = true,
47     bmp = false;
48
49   static final String[] PIXFORMATSTR = {
50     "RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "",
51     "CMYK"
52   };
53
54   static final String[] SUBNAME_LONG = {
55     "4:4:4", "4:2:2", "4:2:0", "GRAY", "4:4:0", "4:1:1", "4:4:1"
56   };
57
58   static final String[] SUBNAME = {
59     "444", "422", "420", "GRAY", "440", "411", "441"
60   };
61
62   static final String[] CSNAME = {
63     "RGB", "YCbCr", "GRAY", "CMYK", "YCCK"
64   };
65
66   private static TJScalingFactor sf = TJ.UNSCALED;
67   private static java.awt.Rectangle cr = TJ.UNCROPPED;
68   private static int xformOp = TJTransform.OP_NONE, xformOpt = 0;
69   private static double benchTime = 5.0, warmup = 1.0;
70
71
72   private static class DummyDCTFilter implements TJCustomFilter {
73     public void customFilter(ShortBuffer coeffBuffer, Rectangle bufferRegion,
74                              Rectangle planeRegion, int componentID,
75                              int transformID, TJTransform transform) {
76       for (int i = 0; i < bufferRegion.width * bufferRegion.height; i++)
77         coeffBuffer.put(i, (short)(-coeffBuffer.get(i)));
78     }
79   }
80
81   private static DummyDCTFilter customFilter;
82
83
84   @SuppressWarnings("checkstyle:HiddenField")
85   private static boolean isCropped(java.awt.Rectangle cr) {
86     return (cr.x != 0 || cr.y != 0 || cr.width != 0 || cr.height != 0);
87   }
88
89   private static int getCroppedWidth(int width) {
90     if (isCropped(cr))
91       return (cr.width != 0 ? cr.width : sf.getScaled(width) - cr.x);
92     else
93       return sf.getScaled(width);
94   }
95
96   private static int getCroppedHeight(int height) {
97     if (isCropped(cr))
98       return (cr.height != 0 ? cr.height : sf.getScaled(height) - cr.y);
99     else
100       return sf.getScaled(height);
101   }
102
103
104   static double getTime() {
105     return (double)System.nanoTime() / 1.0e9;
106   }
107
108
109   private static String tjErrorMsg;
110   private static int tjErrorCode = -1;
111
112   static void handleTJException(TJException e) throws TJException {
113     String errorMsg = e.getMessage();
114     int errorCode = e.getErrorCode();
115
116     if (!stopOnWarning && errorCode == TJ.ERR_WARNING) {
117       if (tjErrorMsg == null || !tjErrorMsg.equals(errorMsg) ||
118           tjErrorCode != errorCode) {
119         tjErrorMsg = errorMsg;
120         tjErrorCode = errorCode;
121         System.out.println("WARNING: " + errorMsg);
122       }
123     } else
124       throw e;
125   }
126
127
128   static String formatName(int subsamp, int cs) {
129     if (quiet != 0) {
130       if (lossless)
131         return String.format("%-2d/LOSSLESS   ", precision);
132       else if (subsamp == TJ.SAMP_UNKNOWN)
133         return String.format("%-2d/%-5s      ", precision, CSNAME[cs]);
134       else
135         return String.format("%-2d/%-5s/%-5s", precision, CSNAME[cs],
136                              SUBNAME_LONG[subsamp]);
137     } else {
138       if (lossless)
139         return "Lossless";
140       else if (subsamp == TJ.SAMP_UNKNOWN)
141         return CSNAME[cs];
142       else
143         return CSNAME[cs] + " " + SUBNAME_LONG[subsamp];
144     }
145   }
146
147
148   static String sigFig(double val, int figs) {
149     String format;
150     int digitsAfterDecimal = figs - (int)Math.ceil(Math.log10(Math.abs(val)));
151
152     if (digitsAfterDecimal < 1)
153       format = new String("%.0f");
154     else
155       format = new String("%." + digitsAfterDecimal + "f");
156     return String.format(format, val);
157   }
158
159
160   /* Decompression test */
161   static void decomp(byte[][] jpegBufs, int[] jpegSizes, Object dstBuf, int w,
162                      int h, int subsamp, int jpegQual, String fileName,
163                      int tilew, int tileh) throws Exception {
164     String qualStr = new String(""), sizeStr, tempStr;
165     TJDecompressor tjd;
166     double elapsed, elapsedDecode;
167     int ps = TJ.getPixelSize(pf), i, iter = 0;
168     int scaledw, scaledh, pitch;
169     YUVImage yuvImage = null;
170
171     if (lossless)
172       sf = TJ.UNSCALED;
173
174     scaledw = sf.getScaled(w);
175     scaledh = sf.getScaled(h);
176
177     if (jpegQual > 0)
178       qualStr = new String((lossless ? "_PSV" : "_Q") + jpegQual);
179
180     tjd = new TJDecompressor();
181     tjd.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
182     tjd.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
183     tjd.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0);
184     tjd.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
185     tjd.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0);
186
187     if (isCropped(cr)) {
188       try {
189         tjd.setSourceImage(jpegBufs[0], jpegSizes[0]);
190       } catch (TJException e) { handleTJException(e); }
191     }
192     tjd.setScalingFactor(sf);
193     tjd.setCroppingRegion(cr);
194     if (isCropped(cr)) {
195       scaledw = cr.width != 0 ? cr.width : scaledw - cr.x;
196       scaledh = cr.height != 0 ? cr.height : scaledh - cr.y;
197     }
198     pitch = scaledw * ps;
199
200     if (dstBuf == null) {
201       if ((long)pitch * (long)scaledh > (long)Integer.MAX_VALUE)
202         throw new Exception("Image is too large");
203       if (precision == 8)
204         dstBuf = new byte[pitch * scaledh];
205       else
206         dstBuf = new short[pitch * scaledh];
207     }
208
209     /* Set the destination buffer to gray so we know whether the decompressor
210        attempted to write to it */
211     if (precision == 8)
212       Arrays.fill((byte[])dstBuf, (byte)127);
213     else if (precision == 12)
214       Arrays.fill((short[])dstBuf, (short)2047);
215     else
216       Arrays.fill((short[])dstBuf, (short)32767);
217
218     if (doYUV) {
219       int width = doTile ? tilew : scaledw;
220       int height = doTile ? tileh : scaledh;
221
222       yuvImage = new YUVImage(width, yuvAlign, height, subsamp);
223       Arrays.fill(yuvImage.getBuf(), (byte)127);
224     }
225
226     /* Benchmark */
227     iter = -1;
228     elapsed = elapsedDecode = 0.0;
229     while (true) {
230       int tile = 0;
231       double start = getTime();
232
233       for (int y = 0; y < h; y += tileh) {
234         for (int x = 0; x < w; x += tilew, tile++) {
235           int width = doTile ? Math.min(tilew, w - x) : scaledw;
236           int height = doTile ? Math.min(tileh, h - y) : scaledh;
237
238           try {
239             tjd.setSourceImage(jpegBufs[tile], jpegSizes[tile]);
240           } catch (TJException e) { handleTJException(e); }
241           if (doYUV) {
242             yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height,
243                             subsamp);
244             try {
245               tjd.decompressToYUV(yuvImage);
246             } catch (TJException e) { handleTJException(e); }
247             double startDecode = getTime();
248             tjd.setSourceImage(yuvImage);
249             try {
250               tjd.decompress8((byte[])dstBuf, x, y, pitch, pf);
251             } catch (TJException e) { handleTJException(e); }
252             if (iter >= 0)
253               elapsedDecode += getTime() - startDecode;
254           } else {
255             try {
256               if (precision == 8)
257                 tjd.decompress8((byte[])dstBuf, x, y, pitch, pf);
258               else if (precision == 12)
259                 tjd.decompress12((short[])dstBuf, x, y, pitch, pf);
260               else
261                 tjd.decompress16((short[])dstBuf, x, y, pitch, pf);
262             } catch (TJException e) { handleTJException(e); }
263           }
264         }
265       }
266       elapsed += getTime() - start;
267       if (iter >= 0) {
268         iter++;
269         if (elapsed >= benchTime)
270           break;
271       } else if (elapsed >= warmup) {
272         iter = 0;
273         elapsed = elapsedDecode = 0.0;
274       }
275     }
276     if (doYUV)
277       elapsed -= elapsedDecode;
278
279     for (i = 0; i < jpegBufs.length; i++)
280       jpegBufs[i] = null;
281     jpegBufs = null;  jpegSizes = null;
282     System.gc();
283
284     if (quiet != 0) {
285       System.out.format("%-6s%s",
286                         sigFig((double)(w * h) / 1000000. *
287                                (double)iter / elapsed, 4),
288                         quiet == 2 ? "\n" : "  ");
289       if (doYUV)
290         System.out.format("%s\n",
291                           sigFig((double)(w * h) / 1000000. *
292                                  (double)iter / elapsedDecode, 4));
293       else if (quiet != 2)
294         System.out.print("\n");
295     } else {
296       System.out.format("%s --> Frame rate:         %f fps\n",
297                         (doYUV ? "Decomp to YUV" : "Decompress   "),
298                         (double)iter / elapsed);
299       System.out.format("                  Throughput:         %f Megapixels/sec\n",
300                         (double)(w * h) / 1000000. * (double)iter / elapsed);
301       if (doYUV) {
302         System.out.format("YUV Decode    --> Frame rate:         %f fps\n",
303                           (double)iter / elapsedDecode);
304         System.out.format("                  Throughput:         %f Megapixels/sec\n",
305                           (double)(w * h) / 1000000. *
306                           (double)iter / elapsedDecode);
307       }
308     }
309
310     if (!write) return;
311
312     if (sf.getNum() != 1 || sf.getDenom() != 1)
313       sizeStr = new String(sf.getNum() + "_" + sf.getDenom());
314     else if (tilew != w || tileh != h)
315       sizeStr = new String(tilew + "x" + tileh);
316     else
317       sizeStr = new String("full");
318     if (decompOnly)
319       tempStr = new String(fileName + "_" + sizeStr + (bmp ? ".bmp" : ".ppm"));
320     else
321       tempStr = new String(fileName + "_" +
322                            (lossless ? "LOSSLS" : SUBNAME[subsamp]) + qualStr +
323                            "_" + sizeStr + (bmp ? ".bmp" : ".ppm"));
324
325     tjd.saveImage(precision, tempStr, dstBuf, scaledw, 0, scaledh, pf);
326   }
327
328
329   static void fullTest(TJCompressor tjc, Object srcBuf, int w, int h,
330                        int subsamp, int jpegQual, String fileName)
331                        throws Exception {
332     Object tmpBuf;
333     byte[][] jpegBufs;
334     int[] jpegSizes;
335     double start, elapsed, elapsedEncode;
336     int totalJpegSize = 0, tilew, tileh, i, iter;
337     int ps = TJ.getPixelSize(pf);
338     int ntilesw = 1, ntilesh = 1, pitch = w * ps;
339     String pfStr = PIXFORMATSTR[pf];
340     YUVImage yuvImage = null;
341
342     if ((long)pitch * (long)h > (long)Integer.MAX_VALUE)
343       throw new Exception("Image is too large");
344     if (precision == 8)
345       tmpBuf = new byte[pitch * h];
346     else
347       tmpBuf = new short[pitch * h];
348
349     if (quiet == 0)
350       System.out.format(">>>>>  %s (%s) <--> %d-bit JPEG (%s %s%d)  <<<<<\n",
351                         pfStr, bottomUp ? "Bottom-up" : "Top-down", precision,
352                         lossless ? "Lossless" : SUBNAME_LONG[subsamp],
353                         lossless ? "PSV" : "Q", jpegQual);
354
355     tjc.set(TJ.PARAM_SUBSAMP, subsamp);
356     tjc.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
357     tjc.set(TJ.PARAM_OPTIMIZE, optimize ? 1 : 0);
358     tjc.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0);
359     tjc.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0);
360     tjc.set(TJ.PARAM_LOSSLESS, lossless ? 1 : 0);
361     if (lossless)
362       tjc.set(TJ.PARAM_LOSSLESSPSV, jpegQual);
363     else
364       tjc.set(TJ.PARAM_QUALITY, jpegQual);
365     tjc.set(TJ.PARAM_RESTARTBLOCKS, restartIntervalBlocks);
366     tjc.set(TJ.PARAM_RESTARTROWS, restartIntervalRows);
367
368     for (tilew = doTile ? 8 : w, tileh = doTile ? 8 : h; ;
369          tilew *= 2, tileh *= 2) {
370       if (tilew > w)
371         tilew = w;
372       if (tileh > h)
373         tileh = h;
374       ntilesw = (w + tilew - 1) / tilew;
375       ntilesh = (h + tileh - 1) / tileh;
376
377       jpegBufs =
378         new byte[ntilesw * ntilesh][TJ.bufSize(tilew, tileh, subsamp)];
379       jpegSizes = new int[ntilesw * ntilesh];
380
381       /* Compression test */
382       if (quiet == 1)
383         System.out.format("%-4s(%s)  %-2d/%-6s %-3d   ", pfStr,
384                           bottomUp ? "BU" : "TD", precision,
385                           lossless ? "LOSSLS" : SUBNAME_LONG[subsamp],
386                           jpegQual);
387       if (precision == 8) {
388         for (i = 0; i < h; i++)
389           System.arraycopy((byte[])srcBuf, w * ps * i, (byte[])tmpBuf,
390                            pitch * i, w * ps);
391       } else {
392         for (i = 0; i < h; i++)
393           System.arraycopy((short[])srcBuf, w * ps * i, (short[])tmpBuf,
394                            pitch * i, w * ps);
395       }
396
397       if (doYUV) {
398         yuvImage = new YUVImage(tilew, yuvAlign, tileh, subsamp);
399         Arrays.fill(yuvImage.getBuf(), (byte)127);
400       }
401
402       /* Benchmark */
403       iter = -1;
404       elapsed = elapsedEncode = 0.0;
405       while (true) {
406         int tile = 0;
407
408         totalJpegSize = 0;
409         start = getTime();
410         for (int y = 0; y < h; y += tileh) {
411           for (int x = 0; x < w; x += tilew, tile++) {
412             int width = Math.min(tilew, w - x);
413             int height = Math.min(tileh, h - y);
414
415             if (precision == 8)
416               tjc.setSourceImage((byte[])srcBuf, x, y, width, pitch, height,
417                                  pf);
418             else if (precision == 12)
419               tjc.setSourceImage12((short[])srcBuf, x, y, width, pitch, height,
420                                    pf);
421             else
422               tjc.setSourceImage16((short[])srcBuf, x, y, width, pitch, height,
423                                    pf);
424             if (doYUV) {
425               double startEncode = getTime();
426
427               yuvImage.setBuf(yuvImage.getBuf(), width, yuvAlign, height,
428                               subsamp);
429               tjc.encodeYUV(yuvImage);
430               if (iter >= 0)
431                 elapsedEncode += getTime() - startEncode;
432               tjc.setSourceImage(yuvImage);
433             }
434             tjc.compress(jpegBufs[tile]);
435             jpegSizes[tile] = tjc.getCompressedSize();
436             totalJpegSize += jpegSizes[tile];
437           }
438         }
439         elapsed += getTime() - start;
440         if (iter >= 0) {
441           iter++;
442           if (elapsed >= benchTime)
443             break;
444         } else if (elapsed >= warmup) {
445           iter = 0;
446           elapsed = elapsedEncode = 0.0;
447         }
448       }
449       if (doYUV)
450         elapsed -= elapsedEncode;
451
452       if (quiet == 1)
453         System.out.format("%-5d  %-5d   ", tilew, tileh);
454       if (quiet != 0) {
455         if (doYUV)
456           System.out.format("%-6s%s",
457                             sigFig((double)(w * h) / 1000000. *
458                                    (double)iter / elapsedEncode, 4),
459                             quiet == 2 ? "\n" : "  ");
460         System.out.format("%-6s%s",
461                           sigFig((double)(w * h) / 1000000. *
462                                  (double)iter / elapsed, 4),
463                           quiet == 2 ? "\n" : "  ");
464         System.out.format("%-6s%s",
465                           sigFig((double)(w * h * ps) / (double)totalJpegSize,
466                                  4),
467                           quiet == 2 ? "\n" : "  ");
468       } else {
469         System.out.format("\n%s size: %d x %d\n", doTile ? "Tile" : "Image",
470                           tilew, tileh);
471         if (doYUV) {
472           System.out.format("Encode YUV    --> Frame rate:         %f fps\n",
473                             (double)iter / elapsedEncode);
474           System.out.format("                  Output image size:  %d bytes\n",
475                             yuvImage.getSize());
476           System.out.format("                  Compression ratio:  %f:1\n",
477                             (double)(w * h * ps) / (double)yuvImage.getSize());
478           System.out.format("                  Throughput:         %f Megapixels/sec\n",
479                             (double)(w * h) / 1000000. *
480                             (double)iter / elapsedEncode);
481           System.out.format("                  Output bit stream:  %f Megabits/sec\n",
482                             (double)yuvImage.getSize() * 8. / 1000000. *
483                             (double)iter / elapsedEncode);
484         }
485         System.out.format("%s --> Frame rate:         %f fps\n",
486                           doYUV ? "Comp from YUV" : "Compress     ",
487                           (double)iter / elapsed);
488         System.out.format("                  Output image size:  %d bytes\n",
489                           totalJpegSize);
490         System.out.format("                  Compression ratio:  %f:1\n",
491                           (double)(w * h * ps) / (double)totalJpegSize);
492         System.out.format("                  Throughput:         %f Megapixels/sec\n",
493                           (double)(w * h) / 1000000. * (double)iter / elapsed);
494         System.out.format("                  Output bit stream:  %f Megabits/sec\n",
495                           (double)totalJpegSize * 8. / 1000000. *
496                           (double)iter / elapsed);
497       }
498       if (tilew == w && tileh == h && write) {
499         String tempStr = fileName + "_" +
500                          (lossless ? "LOSSLS" : SUBNAME[subsamp]) + "_" +
501                          (lossless ? "PSV" : "Q") + jpegQual + ".jpg";
502         FileOutputStream fos = new FileOutputStream(tempStr);
503
504         fos.write(jpegBufs[0], 0, jpegSizes[0]);
505         fos.close();
506         if (quiet == 0)
507           System.out.println("Reference image written to " + tempStr);
508       }
509
510       /* Decompression test */
511       if (!compOnly)
512         decomp(jpegBufs, jpegSizes, tmpBuf, w, h, subsamp, jpegQual, fileName,
513                tilew, tileh);
514       else if (quiet == 1)
515         System.out.println("N/A");
516
517       if (tilew == w && tileh == h) break;
518     }
519   }
520
521
522   static void decompTest(String fileName) throws Exception {
523     TJTransformer tjt;
524     byte[][] jpegBufs = null;
525     byte[] srcBuf;
526     int[] jpegSizes = null;
527     int totalJpegSize;
528     double start, elapsed;
529     int ps = TJ.getPixelSize(pf), tile, x, y, iter;
530     // Original image
531     int w = 0, h = 0, ntilesw = 1, ntilesh = 1, subsamp = -1, cs = -1;
532     // Transformed image
533     int minTile = 16, tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
534
535     FileInputStream fis = new FileInputStream(fileName);
536     if (fis.getChannel().size() > (long)Integer.MAX_VALUE)
537       throw new Exception("Image is too large");
538     int srcSize = (int)fis.getChannel().size();
539     srcBuf = new byte[srcSize];
540     fis.read(srcBuf, 0, srcSize);
541     fis.close();
542
543     int index = fileName.lastIndexOf('.');
544     if (index >= 0)
545       fileName = new String(fileName.substring(0, index));
546
547     tjt = new TJTransformer();
548     tjt.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
549     tjt.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
550     tjt.set(TJ.PARAM_FASTUPSAMPLE, fastUpsample ? 1 : 0);
551     tjt.set(TJ.PARAM_FASTDCT, fastDCT ? 1 : 0);
552     tjt.set(TJ.PARAM_SCANLIMIT, limitScans ? 500 : 0);
553
554     try {
555       tjt.setSourceImage(srcBuf, srcSize);
556     } catch (TJException e) { handleTJException(e); }
557     w = tjt.getWidth();
558     h = tjt.getHeight();
559     subsamp = tjt.get(TJ.PARAM_SUBSAMP);
560     precision = tjt.get(TJ.PARAM_PRECISION);
561     cs = tjt.get(TJ.PARAM_COLORSPACE);
562     if (tjt.get(TJ.PARAM_PROGRESSIVE) == 1)
563       System.out.println("JPEG image uses progressive entropy coding\n");
564     if (tjt.get(TJ.PARAM_ARITHMETIC) == 1)
565       System.out.println("JPEG image uses arithmetic entropy coding\n");
566     tjt.set(TJ.PARAM_PROGRESSIVE, progressive ? 1 : 0);
567     tjt.set(TJ.PARAM_ARITHMETIC, arithmetic ? 1 : 0);
568
569     if (cs == TJ.CS_YCCK || cs == TJ.CS_CMYK) {
570       pf = TJ.PF_CMYK;  ps = TJ.getPixelSize(pf);
571     }
572
573     if (tjt.get(TJ.PARAM_LOSSLESS) != 0)
574       sf = TJ.UNSCALED;
575
576     tjt.setScalingFactor(sf);
577     tjt.setCroppingRegion(cr);
578
579     if (quiet == 1) {
580       System.out.println("All performance values in Mpixels/sec\n");
581       System.out.format("Pixel     JPEG             %s  %s   Xform   Comp    Decomp  ",
582                         (doTile ? "Tile " : "Image"),
583                         (doTile ? "Tile " : "Image"));
584       if (doYUV)
585         System.out.print("Decode");
586       System.out.print("\n");
587       System.out.print("Format    Format           Width  Height  Perf    Ratio   Perf    ");
588       if (doYUV)
589         System.out.print("Perf");
590       System.out.println("\n");
591     } else if (quiet == 0)
592       System.out.format(">>>>>  %d-bit JPEG (%s) --> %s (%s)  <<<<<\n",
593                         precision, formatName(subsamp, cs), PIXFORMATSTR[pf],
594                         bottomUp ? "Bottom-up" : "Top-down");
595
596     if (doTile) {
597       if (subsamp == TJ.SAMP_UNKNOWN)
598         throw new Exception("Could not determine subsampling level of JPEG image");
599       minTile = Math.max(TJ.getMCUWidth(subsamp), TJ.getMCUHeight(subsamp));
600     }
601     for (int tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ;
602          tilew *= 2, tileh *= 2) {
603       if (tilew > w)
604         tilew = w;
605       if (tileh > h)
606         tileh = h;
607       ntilesw = (w + tilew - 1) / tilew;
608       ntilesh = (h + tileh - 1) / tileh;
609
610       tw = w;  th = h;  ttilew = tilew;  ttileh = tileh;
611       if (quiet == 0) {
612         System.out.format("\n%s size: %d x %d", (doTile ? "Tile" : "Image"),
613                           ttilew, ttileh);
614         if (sf.getNum() != 1 || sf.getDenom() != 1 || isCropped(cr))
615           System.out.format(" --> %d x %d", getCroppedWidth(tw),
616                             getCroppedHeight(th));
617         System.out.println("");
618       } else if (quiet == 1) {
619         System.out.format("%-4s(%s)  %-14s   ", PIXFORMATSTR[pf],
620                           bottomUp ? "BU" : "TD", formatName(subsamp, cs));
621         System.out.format("%-5d  %-5d   ", getCroppedWidth(tilew),
622                           getCroppedHeight(tileh));
623       }
624
625       tsubsamp = subsamp;
626       if (doTile || xformOp != TJTransform.OP_NONE || xformOpt != 0 ||
627           customFilter != null) {
628         if (xformOp == TJTransform.OP_TRANSPOSE ||
629             xformOp == TJTransform.OP_TRANSVERSE ||
630             xformOp == TJTransform.OP_ROT90 ||
631             xformOp == TJTransform.OP_ROT270) {
632           tw = h;  th = w;  ttilew = tileh;  ttileh = tilew;
633         }
634
635         if (xformOp != TJTransform.OP_NONE &&
636             xformOp != TJTransform.OP_TRANSPOSE && subsamp == TJ.SAMP_UNKNOWN)
637           throw new Exception("Could not determine subsampling level of JPEG image");
638         if ((xformOpt & TJTransform.OPT_GRAY) != 0)
639           tsubsamp = TJ.SAMP_GRAY;
640         if (xformOp == TJTransform.OP_HFLIP ||
641             xformOp == TJTransform.OP_ROT180)
642           tw = tw - (tw % TJ.getMCUWidth(tsubsamp));
643         if (xformOp == TJTransform.OP_VFLIP ||
644             xformOp == TJTransform.OP_ROT180)
645           th = th - (th % TJ.getMCUHeight(tsubsamp));
646         if (xformOp == TJTransform.OP_TRANSVERSE ||
647             xformOp == TJTransform.OP_ROT90)
648           tw = tw - (tw % TJ.getMCUHeight(tsubsamp));
649         if (xformOp == TJTransform.OP_TRANSVERSE ||
650             xformOp == TJTransform.OP_ROT270)
651           th = th - (th % TJ.getMCUWidth(tsubsamp));
652         tntilesw = (tw + ttilew - 1) / ttilew;
653         tntilesh = (th + ttileh - 1) / ttileh;
654
655         if (xformOp == TJTransform.OP_TRANSPOSE ||
656             xformOp == TJTransform.OP_TRANSVERSE ||
657             xformOp == TJTransform.OP_ROT90 ||
658             xformOp == TJTransform.OP_ROT270) {
659           if (tsubsamp == TJ.SAMP_422)
660             tsubsamp = TJ.SAMP_440;
661           else if (tsubsamp == TJ.SAMP_440)
662             tsubsamp = TJ.SAMP_422;
663           else if (tsubsamp == TJ.SAMP_411)
664             tsubsamp = TJ.SAMP_441;
665           else if (tsubsamp == TJ.SAMP_441)
666             tsubsamp = TJ.SAMP_411;
667         }
668
669         TJTransform[] t = new TJTransform[tntilesw * tntilesh];
670         jpegBufs =
671           new byte[tntilesw * tntilesh][TJ.bufSize(ttilew, ttileh, subsamp)];
672
673         for (y = 0, tile = 0; y < th; y += ttileh) {
674           for (x = 0; x < tw; x += ttilew, tile++) {
675             t[tile] = new TJTransform();
676             t[tile].width = Math.min(ttilew, tw - x);
677             t[tile].height = Math.min(ttileh, th - y);
678             t[tile].x = x;
679             t[tile].y = y;
680             t[tile].op = xformOp;
681             t[tile].options = xformOpt | TJTransform.OPT_TRIM;
682             t[tile].cf = customFilter;
683             if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 &&
684                 jpegBufs[tile] != null)
685               jpegBufs[tile] = null;
686           }
687         }
688
689         iter = -1;
690         elapsed = 0.;
691         while (true) {
692           start = getTime();
693           try {
694             tjt.transform(jpegBufs, t);
695           } catch (TJException e) { handleTJException(e); }
696           jpegSizes = tjt.getTransformedSizes();
697           elapsed += getTime() - start;
698           if (iter >= 0) {
699             iter++;
700             if (elapsed >= benchTime)
701               break;
702           } else if (elapsed >= warmup) {
703             iter = 0;
704             elapsed = 0.0;
705           }
706         }
707         t = null;
708
709         for (tile = 0, totalJpegSize = 0; tile < tntilesw * tntilesh; tile++)
710           totalJpegSize += jpegSizes[tile];
711
712         if (quiet != 0) {
713           System.out.format("%-6s%s%-6s%s",
714                             sigFig((double)(w * h) / 1000000. / elapsed, 4),
715                             quiet == 2 ? "\n" : "  ",
716                             sigFig((double)(w * h * ps) /
717                                    (double)totalJpegSize, 4),
718                             quiet == 2 ? "\n" : "  ");
719         } else {
720           System.out.format("Transform     --> Frame rate:         %f fps\n",
721                             1.0 / elapsed);
722           System.out.format("                  Output image size:  %d bytes\n",
723                             totalJpegSize);
724           System.out.format("                  Compression ratio:  %f:1\n",
725                             (double)(w * h * ps) / (double)totalJpegSize);
726           System.out.format("                  Throughput:         %f Megapixels/sec\n",
727                             (double)(w * h) / 1000000. / elapsed);
728           System.out.format("                  Output bit stream:  %f Megabits/sec\n",
729                             (double)totalJpegSize * 8. / 1000000. / elapsed);
730         }
731       } else {
732         if (quiet == 1)
733           System.out.print("N/A     N/A     ");
734         jpegBufs = new byte[1][TJ.bufSize(ttilew, ttileh, subsamp)];
735         jpegSizes = new int[1];
736         jpegBufs[0] = srcBuf;
737         jpegSizes[0] = srcSize;
738       }
739
740       if (w == tilew)
741         ttilew = tw;
742       if (h == tileh)
743         ttileh = th;
744       if ((xformOpt & TJTransform.OPT_NOOUTPUT) == 0)
745         decomp(jpegBufs, jpegSizes, null, tw, th, tsubsamp, 0, fileName,
746                ttilew, ttileh);
747       else if (quiet == 1)
748         System.out.println("N/A");
749
750       jpegBufs = null;
751       jpegSizes = null;
752
753       if (tilew == w && tileh == h) break;
754     }
755   }
756
757
758   static void usage() throws Exception {
759     int i;
760     TJScalingFactor[] scalingFactors = TJ.getScalingFactors();
761     int nsf = scalingFactors.length;
762     String className = new TJBench().getClass().getName();
763
764     System.out.println("\nUSAGE: java " + className);
765     System.out.println("       <Inputimage (BMP|PPM)> <Quality or PSV> [options]\n");
766     System.out.println("       java " + className);
767     System.out.println("       <Inputimage (JPG)> [options]");
768
769     System.out.println("\nGENERAL OPTIONS");
770     System.out.println("---------------");
771     System.out.println("-benchtime T = Run each benchmark for at least T seconds [default = 5.0]");
772     System.out.println("-bmp = Use Windows Bitmap format for output images [default = PPM]");
773     System.out.println("     ** 8-bit data precision only **");
774     System.out.println("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers");
775     System.out.println("-componly = Stop after running compression tests.  Do not test decompression.");
776     System.out.println("-lossless = Generate lossless JPEG images when compressing (implies");
777     System.out.println("     -subsamp 444).  PSV is the predictor selection value (1-7).");
778     System.out.println("-nowrite = Do not write reference or output images (improves consistency of");
779     System.out.println("     benchmark results)");
780     System.out.println("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =");
781     System.out.println("     Use the specified pixel format for packed-pixel source/destination buffers");
782     System.out.println("     [default = BGR]");
783     System.out.println("-cmyk = Indirectly test YCCK JPEG compression/decompression");
784     System.out.println("     (use the CMYK pixel format for packed-pixel source/destination buffers)");
785     System.out.println("-precision N = Use N-bit data precision when compressing [N is 8, 12, or 16;");
786     System.out.println("     default = 8; if N is 16, then -lossless must also be specified]");
787     System.out.println("     (-precision 12 implies -optimize unless -arithmetic is also specified)");
788     System.out.println("-quiet = Output results in tabular rather than verbose format");
789     System.out.println("-restart N = When compressing, add a restart marker every N MCU rows (lossy) or");
790     System.out.println("     N sample rows (lossless) [default = 0 (no restart markers)].  Append 'B'");
791     System.out.println("     to specify the restart marker interval in MCU blocks (lossy) or samples");
792     System.out.println("     (lossless).");
793     System.out.println("-stoponwarning = Immediately discontinue the current");
794     System.out.println("     compression/decompression/transform operation if a warning (non-fatal");
795     System.out.println("     error) occurs");
796     System.out.println("-tile = Compress/transform the input image into separate JPEG tiles of varying");
797     System.out.println("     sizes (useful for measuring JPEG overhead)");
798     System.out.println("-warmup T = Run each benchmark for T seconds [default = 1.0] prior to starting");
799     System.out.println("     the timer, in order to prime the caches and thus improve the consistency");
800     System.out.println("     of the benchmark results");
801
802     System.out.println("\nLOSSY JPEG OPTIONS");
803     System.out.println("------------------");
804     System.out.println("-arithmetic = Use arithmetic entropy coding in JPEG images generated by");
805     System.out.println("     compression and transform operations (can be combined with -progressive)");
806     System.out.println("-crop WxH+X+Y = Decompress only the specified region of the JPEG image, where W");
807     System.out.println("     and H are the width and height of the region (0 = maximum possible width");
808     System.out.println("     or height) and X and Y are the left and upper boundary of the region, all");
809     System.out.println("     specified relative to the scaled image dimensions.  X must be divible by");
810     System.out.println("     the scaled MCU width.");
811     System.out.println("-fastdct = Use the fastest DCT/IDCT algorithm available");
812     System.out.println("-fastupsample = Use the fastest chrominance upsampling algorithm available");
813     System.out.println("-optimize = Use optimized baseline entropy coding in JPEG images generated by");
814     System.out.println("     compession and transform operations");
815     System.out.println("-progressive = Use progressive entropy coding in JPEG images generated by");
816     System.out.println("     compression and transform operations (can be combined with -arithmetic;");
817     System.out.println("     implies -optimize unless -arithmetic is also specified)");
818     System.out.println("-limitscans = Refuse to decompress or transform progressive JPEG images that");
819     System.out.println("     have an unreasonably large number of scans");
820     System.out.println("-scale M/N = When decompressing, scale the width/height of the JPEG image by a");
821     System.out.print("     factor of M/N (M/N = ");
822     for (i = 0; i < nsf; i++) {
823       System.out.format("%d/%d", scalingFactors[i].getNum(),
824                         scalingFactors[i].getDenom());
825       if (nsf == 2 && i != nsf - 1)
826         System.out.print(" or ");
827       else if (nsf > 2) {
828         if (i != nsf - 1)
829           System.out.print(", ");
830         if (i == nsf - 2)
831           System.out.print("or ");
832       }
833       if (i % 8 == 0 && i != 0)
834         System.out.print("\n     ");
835     }
836     System.out.println(")");
837     System.out.println("-subsamp S = When compressing, use the specified level of chrominance");
838     System.out.println("     subsampling (S = 444, 422, 440, 420, 411, 441, or GRAY) [default = test");
839     System.out.println("     Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]");
840     System.out.println("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =");
841     System.out.println("     Perform the specified lossless transform operation on the input image");
842     System.out.println("     prior to decompression (these operations are mutually exclusive)");
843     System.out.println("-grayscale = Transform the input image into a grayscale JPEG image prior to");
844     System.out.println("     decompression (can be combined with the other transform operations above)");
845     System.out.println("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)");
846     System.out.println("     when transforming the input image");
847     System.out.println("-yuv = Compress from/decompress to intermediate planar YUV images");
848     System.out.println("     ** 8-bit data precision only **");
849     System.out.println("-yuvpad N = The number of bytes by which each row in each plane of an");
850     System.out.println("     intermediate YUV image is evenly divisible (N must be a power of 2)");
851     System.out.println("     [default = 1]");
852
853     System.out.println("\nNOTE:  If the quality/PSV is specified as a range (e.g. 90-100 or 1-4), a");
854     System.out.println("separate test will be performed for all values in the range.\n");
855     System.exit(1);
856   }
857
858
859   public static void main(String[] argv) {
860     Object srcBuf = null;
861     int w = 0, h = 0, minQual = -1, maxQual = -1;
862     int minArg = 1, retval = 0;
863     int subsamp = -1;
864     TJCompressor tjc = null;
865
866     try {
867
868       if (argv.length < minArg)
869         usage();
870
871       String tempStr = argv[0].toLowerCase();
872       if (tempStr.endsWith(".jpg") || tempStr.endsWith(".jpeg"))
873         decompOnly = true;
874       if (tempStr.endsWith(".bmp"))
875         bmp = true;
876
877       System.out.println("");
878
879       if (!decompOnly) {
880         minArg = 2;
881         if (argv.length < minArg)
882           usage();
883         String[] quals = argv[1].split("-", 2);
884         try {
885           minQual = Integer.parseInt(quals[0]);
886         } catch (NumberFormatException e) {}
887         if (quals.length > 1) {
888           try {
889             maxQual = Integer.parseInt(quals[1]);
890           } catch (NumberFormatException e) {}
891         }
892         if (maxQual < minQual)
893           maxQual = minQual;
894       }
895
896       if (argv.length > minArg) {
897         for (int i = minArg; i < argv.length; i++) {
898           if (argv[i].equalsIgnoreCase("-tile")) {
899             doTile = true;  xformOpt |= TJTransform.OPT_CROP;
900           } else if (argv[i].equalsIgnoreCase("-precision") &&
901                      i < argv.length - 1) {
902             int temp = 0;
903
904             try {
905               temp = Integer.parseInt(argv[++i]);
906             } catch (NumberFormatException e) {}
907             if (temp == 8 || temp == 12 || temp == 16)
908               precision = temp;
909             else
910               usage();
911           } else if (argv[i].equalsIgnoreCase("-fastupsample")) {
912             System.out.println("Using fastest upsampling algorithm\n");
913             fastUpsample = true;
914           } else if (argv[i].equalsIgnoreCase("-fastdct")) {
915             System.out.println("Using fastest DCT/IDCT algorithm\n");
916             fastDCT = true;
917           } else if (argv[i].equalsIgnoreCase("-optimize")) {
918             System.out.println("Using optimized baseline entropy coding\n");
919             optimize = true;
920             xformOpt |= TJTransform.OPT_OPTIMIZE;
921           } else if (argv[i].equalsIgnoreCase("-progressive")) {
922             System.out.println("Using progressive entropy coding\n");
923             progressive = true;
924             xformOpt |= TJTransform.OPT_PROGRESSIVE;
925           } else if (argv[i].equalsIgnoreCase("-arithmetic")) {
926             System.out.println("Using arithmetic entropy coding\n");
927             arithmetic = true;
928             xformOpt |= TJTransform.OPT_ARITHMETIC;
929           } else if (argv[i].equalsIgnoreCase("-lossless")) {
930             lossless = true;
931             subsamp = TJ.SAMP_444;
932           } else if (argv[i].equalsIgnoreCase("-rgb"))
933             pf = TJ.PF_RGB;
934           else if (argv[i].equalsIgnoreCase("-rgbx"))
935             pf = TJ.PF_RGBX;
936           else if (argv[i].equalsIgnoreCase("-bgr"))
937             pf = TJ.PF_BGR;
938           else if (argv[i].equalsIgnoreCase("-bgrx"))
939             pf = TJ.PF_BGRX;
940           else if (argv[i].equalsIgnoreCase("-xbgr"))
941             pf = TJ.PF_XBGR;
942           else if (argv[i].equalsIgnoreCase("-xrgb"))
943             pf = TJ.PF_XRGB;
944           else if (argv[i].equalsIgnoreCase("-cmyk"))
945             pf = TJ.PF_CMYK;
946           else if (argv[i].equalsIgnoreCase("-bottomup"))
947             bottomUp = true;
948           else if (argv[i].equalsIgnoreCase("-quiet"))
949             quiet = 1;
950           else if (argv[i].equalsIgnoreCase("-qq"))
951             quiet = 2;
952           else if (argv[i].equalsIgnoreCase("-scale") && i < argv.length - 1) {
953             int temp1 = 0, temp2 = 0;
954             boolean match = false, scanned = true;
955             Scanner scanner = new Scanner(argv[++i]).useDelimiter("/");
956
957             try {
958               temp1 = scanner.nextInt();
959               temp2 = scanner.nextInt();
960             } catch (Exception e) {}
961             if (temp2 <= 0) temp2 = 1;
962             if (temp1 > 0) {
963               TJScalingFactor[] scalingFactors = TJ.getScalingFactors();
964
965               for (int j = 0; j < scalingFactors.length; j++) {
966                 if ((double)temp1 / (double)temp2 ==
967                     (double)scalingFactors[j].getNum() /
968                     (double)scalingFactors[j].getDenom()) {
969                   sf = scalingFactors[j];
970                   match = true;  break;
971                 }
972               }
973               if (!match) usage();
974             } else
975               usage();
976           } else if (argv[i].equalsIgnoreCase("-crop") &&
977                      i < argv.length - 1) {
978             int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1;
979             Scanner scanner = new Scanner(argv[++i]).useDelimiter("x|\\+");
980
981             try {
982               temp1 = scanner.nextInt();
983               temp2 = scanner.nextInt();
984               temp3 = scanner.nextInt();
985               temp4 = scanner.nextInt();
986             } catch (Exception e) {}
987
988             if (temp1 < 0 || temp2 < 0 || temp3 < 0 || temp4 < 0)
989               usage();
990             cr.width = temp1;  cr.height = temp2;  cr.x = temp3;  cr.y = temp4;
991           } else if (argv[i].equalsIgnoreCase("-hflip"))
992             xformOp = TJTransform.OP_HFLIP;
993           else if (argv[i].equalsIgnoreCase("-vflip"))
994             xformOp = TJTransform.OP_VFLIP;
995           else if (argv[i].equalsIgnoreCase("-transpose"))
996             xformOp = TJTransform.OP_TRANSPOSE;
997           else if (argv[i].equalsIgnoreCase("-transverse"))
998             xformOp = TJTransform.OP_TRANSVERSE;
999           else if (argv[i].equalsIgnoreCase("-rot90"))
1000             xformOp = TJTransform.OP_ROT90;
1001           else if (argv[i].equalsIgnoreCase("-rot180"))
1002             xformOp = TJTransform.OP_ROT180;
1003           else if (argv[i].equalsIgnoreCase("-rot270"))
1004             xformOp = TJTransform.OP_ROT270;
1005           else if (argv[i].equalsIgnoreCase("-grayscale"))
1006             xformOpt |= TJTransform.OPT_GRAY;
1007           else if (argv[i].equalsIgnoreCase("-custom"))
1008             customFilter = new DummyDCTFilter();
1009           else if (argv[i].equalsIgnoreCase("-nooutput"))
1010             xformOpt |= TJTransform.OPT_NOOUTPUT;
1011           else if (argv[i].equalsIgnoreCase("-copynone"))
1012             xformOpt |= TJTransform.OPT_COPYNONE;
1013           else if (argv[i].equalsIgnoreCase("-benchtime") &&
1014                    i < argv.length - 1) {
1015             double temp = -1;
1016
1017             try {
1018               temp = Double.parseDouble(argv[++i]);
1019             } catch (NumberFormatException e) {}
1020             if (temp > 0.0)
1021               benchTime = temp;
1022             else
1023               usage();
1024           } else if (argv[i].equalsIgnoreCase("-warmup") &&
1025                      i < argv.length - 1) {
1026             double temp = -1;
1027
1028             try {
1029               temp = Double.parseDouble(argv[++i]);
1030             } catch (NumberFormatException e) {}
1031             if (temp >= 0.0) {
1032               warmup = temp;
1033               System.out.format("Warmup time = %.1f seconds\n\n", warmup);
1034             } else
1035               usage();
1036           } else if (argv[i].equalsIgnoreCase("-bmp"))
1037             bmp = true;
1038           else if (argv[i].equalsIgnoreCase("-yuv")) {
1039             System.out.println("Testing planar YUV encoding/decoding\n");
1040             doYUV = true;
1041           } else if (argv[i].equalsIgnoreCase("-yuvpad") &&
1042                      i < argv.length - 1) {
1043             int temp = 0;
1044
1045             try {
1046               temp = Integer.parseInt(argv[++i]);
1047             } catch (NumberFormatException e) {}
1048             if (temp >= 1 && (temp & (temp - 1)) == 0)
1049               yuvAlign = temp;
1050             else
1051               usage();
1052           } else if (argv[i].equalsIgnoreCase("-subsamp") &&
1053                      i < argv.length - 1) {
1054             i++;
1055             if (argv[i].toUpperCase().startsWith("G"))
1056               subsamp = TJ.SAMP_GRAY;
1057             else if (argv[i].equals("444"))
1058               subsamp = TJ.SAMP_444;
1059             else if (argv[i].equals("422"))
1060               subsamp = TJ.SAMP_422;
1061             else if (argv[i].equals("440"))
1062               subsamp = TJ.SAMP_440;
1063             else if (argv[i].equals("420"))
1064               subsamp = TJ.SAMP_420;
1065             else if (argv[i].equals("411"))
1066               subsamp = TJ.SAMP_411;
1067             else if (argv[i].equals("441"))
1068               subsamp = TJ.SAMP_441;
1069             else
1070               usage();
1071           } else if (argv[i].equalsIgnoreCase("-componly"))
1072             compOnly = true;
1073           else if (argv[i].equalsIgnoreCase("-nowrite"))
1074             write = false;
1075           else if (argv[i].equalsIgnoreCase("-limitscans"))
1076             limitScans = true;
1077           else if (argv[i].equalsIgnoreCase("-restart") &&
1078                    i < argv.length - 1) {
1079             int temp = -1;
1080             String arg = argv[++i];
1081             Scanner scanner = new Scanner(arg).useDelimiter("b|B");
1082
1083             try {
1084               temp = scanner.nextInt();
1085             } catch (Exception e) {}
1086
1087             if (temp < 0 || temp > 65535 || scanner.hasNext())
1088               usage();
1089             if (arg.endsWith("B") || arg.endsWith("b"))
1090               restartIntervalBlocks = temp;
1091             else
1092               restartIntervalRows = temp;
1093           } else if (argv[i].equalsIgnoreCase("-stoponwarning"))
1094             stopOnWarning = true;
1095           else usage();
1096         }
1097       }
1098
1099       if (precision == 16 && !lossless)
1100         throw new Exception("-lossless must be specified along with -precision 16");
1101       if (precision != 8 && doYUV)
1102         throw new Exception("-yuv requires 8-bit data precision");
1103       if (lossless && doYUV)
1104         throw new Exception("ERROR: -lossless and -yuv are incompatible");
1105
1106       if ((sf.getNum() != 1 || sf.getDenom() != 1) && doTile) {
1107         System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
1108         System.out.println("work when scaled decompression is enabled.\n");
1109         doTile = false;
1110         xformOpt &= (~TJTransform.OPT_CROP);
1111       }
1112
1113       if (isCropped(cr)) {
1114         if (!decompOnly)
1115           throw new Exception("ERROR: Partial image decompression can only be enabled for JPEG input images");
1116         if (doTile) {
1117           System.out.println("Disabling tiled compression/decompression tests, because those tests do not");
1118           System.out.println("work when partial image decompression is enabled.\n");
1119           doTile = false;
1120           xformOpt &= (~TJTransform.OPT_CROP);
1121         }
1122         if (doYUV)
1123           throw new Exception("ERROR: -crop and -yuv are incompatible");
1124       }
1125
1126       if (!decompOnly) {
1127         int[] width = new int[1], height = new int[1],
1128           pixelFormat = new int[1];
1129
1130         tjc = new TJCompressor();
1131         tjc.set(TJ.PARAM_STOPONWARNING, stopOnWarning ? 1 : 0);
1132         tjc.set(TJ.PARAM_BOTTOMUP, bottomUp ? 1 : 0);
1133
1134         pixelFormat[0] = pf;
1135         srcBuf = tjc.loadImage(precision, argv[0], width, 1, height,
1136                                pixelFormat);
1137         w = width[0];  h = height[0];  pf = pixelFormat[0];
1138         int index = -1;
1139         if ((index = argv[0].lastIndexOf('.')) >= 0)
1140           argv[0] = argv[0].substring(0, index);
1141       }
1142
1143       if (quiet == 1 && !decompOnly) {
1144         System.out.println("All performance values in Mpixels/sec\n");
1145         System.out.format("Pixel     JPEG      JPEG  %s  %s   ",
1146                           (doTile ? "Tile " : "Image"),
1147                           (doTile ? "Tile " : "Image"));
1148         if (doYUV)
1149           System.out.print("Encode  ");
1150         System.out.print("Comp    Comp    Decomp  ");
1151         if (doYUV)
1152           System.out.print("Decode");
1153         System.out.print("\n");
1154         System.out.format("Format    Format    %s  Width  Height  ",
1155                           lossless ? "PSV " : "Qual");
1156         if (doYUV)
1157           System.out.print("Perf    ");
1158         System.out.print("Perf    Ratio   Perf    ");
1159         if (doYUV)
1160           System.out.print("Perf");
1161         System.out.println("\n");
1162       }
1163
1164       if (decompOnly) {
1165         decompTest(argv[0]);
1166         System.out.println("");
1167         System.exit(retval);
1168       }
1169
1170       System.gc();
1171       if (lossless) {
1172         if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7)
1173           throw new Exception("PSV must be between 1 and 7.");
1174       } else {
1175         if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100)
1176           throw new Exception("Quality must be between 1 and 100.");
1177       }
1178       if (subsamp >= 0 && subsamp < TJ.NUMSAMP) {
1179         for (int i = maxQual; i >= minQual; i--)
1180           fullTest(tjc, srcBuf, w, h, subsamp, i, argv[0]);
1181         System.out.println("");
1182       } else {
1183         if (pf != TJ.PF_CMYK) {
1184           for (int i = maxQual; i >= minQual; i--)
1185             fullTest(tjc, srcBuf, w, h, TJ.SAMP_GRAY, i, argv[0]);
1186           System.out.println("");
1187           System.gc();
1188         }
1189         for (int i = maxQual; i >= minQual; i--)
1190           fullTest(tjc, srcBuf, w, h, TJ.SAMP_420, i, argv[0]);
1191         System.out.println("");
1192         System.gc();
1193         for (int i = maxQual; i >= minQual; i--)
1194           fullTest(tjc, srcBuf, w, h, TJ.SAMP_422, i, argv[0]);
1195         System.out.println("");
1196         System.gc();
1197         for (int i = maxQual; i >= minQual; i--)
1198           fullTest(tjc, srcBuf, w, h, TJ.SAMP_444, i, argv[0]);
1199         System.out.println("");
1200       }
1201
1202     } catch (Exception e) {
1203       if (e instanceof TJException) {
1204         TJException tje = (TJException)e;
1205
1206         System.out.println((tje.getErrorCode() == TJ.ERR_WARNING ?
1207                             "WARNING: " : "ERROR: ") + tje.getMessage());
1208       } else
1209         System.out.println("ERROR: " + e.getMessage());
1210       e.printStackTrace();
1211       retval = -1;
1212     }
1213
1214     System.exit(retval);
1215   }
1216
1217 }