1 /*
   2  * Copyright (c) 2006, 2019, Oracle and/or its affiliates. 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
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 
  40 
  41 package j2dbench.tests.iio;
  42 
  43 import java.awt.Component;
  44 import java.awt.Graphics;
  45 import java.awt.Image;
  46 import java.awt.MediaTracker;
  47 import java.awt.Toolkit;
  48 import java.awt.image.BufferedImage;
  49 import java.io.BufferedInputStream;
  50 import java.io.ByteArrayInputStream;
  51 import java.io.ByteArrayOutputStream;
  52 import java.io.File;
  53 import java.io.FileInputStream;
  54 import java.io.IOException;
  55 import java.io.InputStream;
  56 import java.io.OutputStream;
  57 import java.net.URL;
  58 import java.util.ArrayList;
  59 import java.util.List;
  60 import javax.imageio.ImageIO;
  61 import javax.imageio.ImageReader;
  62 import javax.imageio.event.IIOReadProgressListener;
  63 import javax.imageio.spi.IIORegistry;
  64 import javax.imageio.spi.ImageReaderSpi;
  65 import javax.imageio.stream.ImageInputStream;
  66 
  67 import j2dbench.Group;
  68 import j2dbench.Modifier;
  69 import j2dbench.Option;
  70 import j2dbench.Result;
  71 import j2dbench.Test;
  72 import j2dbench.TestEnvironment;
  73 
  74 abstract class InputImageTests extends InputTests {
  75 
  76     private static final int TEST_TOOLKIT     = 1;
  77     private static final int TEST_IMAGEIO     = 2;
  78     private static final int TEST_IMAGEREADER = 3;
  79 
  80     private static Group imageRoot;
  81 
  82     private static Group toolkitRoot;
  83     private static Group toolkitOptRoot;
  84     private static Option toolkitReadFormatList;
  85     private static Group toolkitTestRoot;
  86 
  87     private static Group imageioRoot;
  88     private static Group imageioOptRoot;
  89     private static ImageReaderSpi[] imageioReaderSpis;
  90     private static String[] imageioReadFormatShortNames;
  91     private static Option imageioReadFormatList;
  92     private static Group imageioTestRoot;
  93 
  94     private static Group imageReaderRoot;
  95     private static Group imageReaderOptRoot;
  96     private static Option seekForwardOnlyTog;
  97     private static Option ignoreMetadataTog;
  98     private static Option installListenerTog;
  99     private static Group imageReaderTestRoot;
 100 
 101     public static void init() {
 102         imageRoot = new Group(inputRoot, "image", "Image Reading Benchmarks");
 103         imageRoot.setTabbed();
 104 
 105         // Toolkit Benchmarks
 106         toolkitRoot = new Group(imageRoot, "toolkit", "Toolkit");
 107 
 108         toolkitOptRoot = new Group(toolkitRoot, "opts", "Toolkit Options");
 109         String[] tkFormats = new String[] {"gif", "jpg", "png"};
 110         toolkitReadFormatList =
 111             new Option.ObjectList(toolkitOptRoot,
 112                                   "format", "Image Format",
 113                                   tkFormats, tkFormats,
 114                                   tkFormats, tkFormats,
 115                                   0x0);
 116 
 117         toolkitTestRoot = new Group(toolkitRoot, "tests", "Toolkit Tests");
 118         new ToolkitCreateImage();
 119 
 120         // Image I/O Benchmarks
 121         if (hasImageIO) {
 122             imageioRoot = new Group(imageRoot, "imageio", "Image I/O");
 123 
 124             // Image I/O Options
 125             imageioOptRoot = new Group(imageioRoot, "opts",
 126                                        "Image I/O Options");
 127             initIIOReadFormats();
 128             imageioReadFormatList =
 129                 new Option.ObjectList(imageioOptRoot,
 130                                       "format", "Image Format",
 131                                       imageioReadFormatShortNames,
 132                                       imageioReaderSpis,
 133                                       imageioReadFormatShortNames,
 134                                       imageioReadFormatShortNames,
 135                                       0x0);
 136 
 137             // Image I/O Tests
 138             imageioTestRoot = new Group(imageioRoot, "tests",
 139                                         "Image I/O Tests");
 140             new ImageIORead();
 141 
 142             // ImageReader Options
 143             imageReaderRoot = new Group(imageioRoot, "reader",
 144                                         "ImageReader Benchmarks");
 145             imageReaderOptRoot = new Group(imageReaderRoot, "opts",
 146                                            "ImageReader Options");
 147             seekForwardOnlyTog =
 148                 new Option.Toggle(imageReaderOptRoot,
 149                                   "seekForwardOnly",
 150                                   "Seek Forward Only",
 151                                   Option.Toggle.On);
 152             ignoreMetadataTog =
 153                 new Option.Toggle(imageReaderOptRoot,
 154                                   "ignoreMetadata",
 155                                   "Ignore Metadata",
 156                                   Option.Toggle.On);
 157             installListenerTog =
 158                 new Option.Toggle(imageReaderOptRoot,
 159                                   "installListener",
 160                                   "Install Progress Listener",
 161                                   Option.Toggle.Off);
 162 
 163             // ImageReader Tests
 164             imageReaderTestRoot = new Group(imageReaderRoot, "tests",
 165                                             "ImageReader Tests");
 166             new ImageReaderRead();
 167             new ImageReaderGetImageMetadata();
 168         }
 169     }
 170 
 171     private static void initIIOReadFormats() {
 172         List spis = new ArrayList();
 173         List shortNames = new ArrayList();
 174 
 175         ImageIO.scanForPlugins();
 176         IIORegistry registry = IIORegistry.getDefaultInstance();
 177         java.util.Iterator readerspis =
 178             registry.getServiceProviders(ImageReaderSpi.class, false);
 179         while (readerspis.hasNext()) {
 180             // REMIND: there could be more than one non-core plugin for
 181             // a particular format, as is the case for JPEG2000 in the JAI
 182             // IIO Tools package, so we should support that somehow
 183             ImageReaderSpi spi = (ImageReaderSpi)readerspis.next();
 184             String klass = spi.getClass().getName();
 185             String format = spi.getFormatNames()[0].toLowerCase();
 186             String suffix = spi.getFileSuffixes()[0].toLowerCase();
 187             if (suffix == null || suffix.isEmpty()) {
 188                 suffix = format;
 189             }
 190             String shortName;
 191             if (klass.startsWith("com.sun.imageio.plugins")) {
 192                 shortName = "core-" + suffix;
 193             } else {
 194                 shortName = "ext-" + suffix;
 195             }
 196             spis.add(spi);
 197             shortNames.add(shortName);
 198         }
 199 
 200         imageioReaderSpis = new ImageReaderSpi[spis.size()];
 201         imageioReaderSpis = (ImageReaderSpi[])spis.toArray(imageioReaderSpis);
 202         imageioReadFormatShortNames = new String[shortNames.size()];
 203         imageioReadFormatShortNames =
 204             (String[])shortNames.toArray(imageioReadFormatShortNames);
 205     }
 206 
 207     protected InputImageTests(Group parent,
 208                               String nodeName, String description)
 209     {
 210         super(parent, nodeName, description);
 211     }
 212 
 213     public void cleanupTest(TestEnvironment env, Object ctx) {
 214         Context iioctx = (Context)ctx;
 215         iioctx.cleanup(env);
 216     }
 217 
 218     private static class Context extends InputTests.Context {
 219         String format;
 220         BufferedImage image;
 221         ImageReader reader;
 222         boolean seekForwardOnly;
 223         boolean ignoreMetadata;
 224 
 225         Context(TestEnvironment env, Result result, int testType) {
 226             super(env, result);
 227 
 228             String content = (String)env.getModifier(contentList);
 229             if (content == null) {
 230                 content = CONTENT_BLANK;
 231             }
 232             // REMIND: add option for non-opaque images
 233             image = createBufferedImage(size, size, content, false);
 234 
 235             result.setUnits(size*size);
 236             result.setUnitName("pixel");
 237 
 238             if (testType == TEST_IMAGEIO || testType == TEST_IMAGEREADER) {
 239                 ImageReaderSpi readerspi =
 240                     (ImageReaderSpi)env.getModifier(imageioReadFormatList);
 241                 format = readerspi.getFileSuffixes()[0].toLowerCase();
 242                 if (testType == TEST_IMAGEREADER) {
 243                     seekForwardOnly = env.isEnabled(seekForwardOnlyTog);
 244                     ignoreMetadata = env.isEnabled(ignoreMetadataTog);
 245                     try {
 246                         reader = readerspi.createReaderInstance();
 247                     } catch (IOException e) {
 248                         System.err.println("error creating reader");
 249                         e.printStackTrace();
 250                     }
 251                     if (env.isEnabled(installListenerTog)) {
 252                         reader.addIIOReadProgressListener(
 253                             new ReadProgressListener());
 254                     }
 255                 }
 256                 if (format.equals("wbmp")) {
 257                     // REMIND: this is a hack to create an image that the
 258                     //         WBMPImageWriter can handle (a better approach
 259                     //         would involve checking the ImageTypeSpecifier
 260                     //         of the writer's default image param)
 261                     BufferedImage newimg =
 262                         new BufferedImage(size, size,
 263                                           BufferedImage.TYPE_BYTE_BINARY);
 264                     Graphics g = newimg.createGraphics();
 265                     g.drawImage(image, 0, 0, null);
 266                     g.dispose();
 267                     image = newimg;
 268                 }
 269             } else if (testType == TEST_TOOLKIT) {
 270                 format = (String)env.getModifier(toolkitReadFormatList);
 271             } else { // testType == TEST_JPEGCODEC
 272                 format = "jpeg";
 273             }
 274 
 275             initInput();
 276         }
 277 
 278         void initContents(File f) throws IOException {
 279             ImageIO.write(image, format, f);
 280         }
 281 
 282         void initContents(OutputStream out) throws IOException {
 283             ImageIO.write(image, format, out);
 284         }
 285 
 286         void cleanup(TestEnvironment env) {
 287             super.cleanup(env);
 288             if (reader != null) {
 289                 reader.dispose();
 290                 reader = null;
 291             }
 292         }
 293     }
 294 
 295     private static class ToolkitCreateImage extends InputImageTests {
 296         private static final Component canvas = new Component() {};
 297 
 298         public ToolkitCreateImage() {
 299             super(toolkitTestRoot,
 300                   "createImage",
 301                   "Toolkit.createImage()");
 302             addDependency(generalSourceRoot,
 303                 new Modifier.Filter() {
 304                     public boolean isCompatible(Object val) {
 305                         // Toolkit handles FILE, URL, and ARRAY, but
 306                         // not FILECHANNEL
 307                         InputType t = (InputType)val;
 308                         return (t.getType() != INPUT_FILECHANNEL);
 309                     }
 310                 });
 311             addDependencies(toolkitOptRoot, true);
 312         }
 313 
 314         public Object initTest(TestEnvironment env, Result result) {
 315             return new Context(env, result, TEST_TOOLKIT);
 316         }
 317 
 318         public void runTest(Object ctx, int numReps) {
 319             final Context ictx = (Context)ctx;
 320             final Object input = ictx.input;
 321             final int inputType = ictx.inputType;
 322             final Toolkit tk = Toolkit.getDefaultToolkit();
 323             final MediaTracker mt = new MediaTracker(canvas);
 324             switch (inputType) {
 325             case INPUT_FILE:
 326                 String filename = ((File)input).getAbsolutePath();
 327                 do {
 328                     try {
 329                         Image img = tk.createImage(filename);
 330                         mt.addImage(img, 0);
 331                         mt.waitForID(0, 0);
 332                         mt.removeImage(img, 0);
 333                     } catch (Exception e) {
 334                         e.printStackTrace();
 335                     }
 336                 } while (--numReps >= 0);
 337                 break;
 338             case INPUT_URL:
 339                 do {
 340                     try {
 341                         Image img = tk.createImage((URL)input);
 342                         mt.addImage(img, 0);
 343                         mt.waitForID(0, 0);
 344                         mt.removeImage(img, 0);
 345                     } catch (Exception e) {
 346                         e.printStackTrace();
 347                     }
 348                 } while (--numReps >= 0);
 349                 break;
 350             case INPUT_ARRAY:
 351                 do {
 352                     try {
 353                         Image img = tk.createImage((byte[])input);
 354                         mt.addImage(img, 0);
 355                         mt.waitForID(0, 0);
 356                         mt.removeImage(img, 0);
 357                     } catch (Exception e) {
 358                         e.printStackTrace();
 359                     }
 360                 } while (--numReps >= 0);
 361                 break;
 362             default:
 363                 throw new IllegalArgumentException("Invalid input type");
 364             }
 365         }
 366     }
 367 
 368     private static class ImageIORead extends InputImageTests {
 369         public ImageIORead() {
 370             super(imageioTestRoot,
 371                   "imageioRead",
 372                   "ImageIO.read()");
 373             addDependency(generalSourceRoot,
 374                 new Modifier.Filter() {
 375                     public boolean isCompatible(Object val) {
 376                         // ImageIO.read() handles FILE, URL, and ARRAY, but
 377                         // not FILECHANNEL (well, I suppose we could create
 378                         // an ImageInputStream from a FileChannel source,
 379                         // but that's not a common use case; FileChannel is
 380                         // better handled by the ImageReader tests below)
 381                         InputType t = (InputType)val;
 382                         return (t.getType() != INPUT_FILECHANNEL);
 383                     }
 384                 });
 385             addDependencies(imageioOptRoot, true);
 386         }
 387 
 388         public Object initTest(TestEnvironment env, Result result) {
 389             return new Context(env, result, TEST_IMAGEIO);
 390         }
 391 
 392         public void runTest(Object ctx, int numReps) {
 393             final Context ictx = (Context)ctx;
 394             final Object input = ictx.input;
 395             final int inputType = ictx.inputType;
 396             switch (inputType) {
 397             case INPUT_FILE:
 398                 do {
 399                     try {
 400                         ImageIO.read((File)input);
 401                     } catch (Exception e) {
 402                         e.printStackTrace();
 403                     }
 404                 } while (--numReps >= 0);
 405                 break;
 406             case INPUT_URL:
 407                 do {
 408                     try {
 409                         ImageIO.read((URL)input);
 410                     } catch (Exception e) {
 411                         e.printStackTrace();
 412                     }
 413                 } while (--numReps >= 0);
 414                 break;
 415             case INPUT_ARRAY:
 416                 do {
 417                     try {
 418                         ByteArrayInputStream bais =
 419                             new ByteArrayInputStream((byte[])input);
 420                         BufferedInputStream bis =
 421                             new BufferedInputStream(bais);
 422                         ImageIO.read(bis);
 423                         bais.close();
 424                     } catch (Exception e) {
 425                         e.printStackTrace();
 426                     }
 427                 } while (--numReps >= 0);
 428                 break;
 429             default:
 430                 throw new IllegalArgumentException("Invalid input type");
 431             }
 432         }
 433     }
 434 
 435     private static class ImageReaderRead extends InputImageTests {
 436         public ImageReaderRead() {
 437             super(imageReaderTestRoot,
 438                   "read",
 439                   "ImageReader.read()");
 440             addDependency(generalSourceRoot);
 441             addDependencies(imageioGeneralOptRoot, true);
 442             addDependencies(imageioOptRoot, true);
 443             addDependencies(imageReaderOptRoot, true);
 444         }
 445 
 446         public Object initTest(TestEnvironment env, Result result) {
 447             return new Context(env, result, TEST_IMAGEREADER);
 448         }
 449 
 450         public void runTest(Object ctx, int numReps) {
 451             final Context ictx = (Context)ctx;
 452             final ImageReader reader = ictx.reader;
 453             final boolean seekForwardOnly = ictx.seekForwardOnly;
 454             final boolean ignoreMetadata = ictx.ignoreMetadata;
 455             do {
 456                 try {
 457                     ImageInputStream iis = ictx.createImageInputStream();
 458                     reader.setInput(iis, seekForwardOnly, ignoreMetadata);
 459                     reader.read(0);
 460                     reader.reset();
 461                     iis.close();
 462                     ictx.closeOriginalStream();
 463                 } catch (IOException e) {
 464                     e.printStackTrace();
 465                 }
 466             } while (--numReps >= 0);
 467         }
 468     }
 469 
 470     private static class ImageReaderGetImageMetadata extends InputImageTests {
 471         public ImageReaderGetImageMetadata() {
 472             super(imageReaderTestRoot,
 473                   "getImageMetadata",
 474                   "ImageReader.getImageMetadata()");
 475             addDependency(generalSourceRoot);
 476             addDependencies(imageioGeneralOptRoot, true);
 477             addDependencies(imageioOptRoot, true);
 478             addDependencies(imageReaderOptRoot, true);
 479         }
 480 
 481         public Object initTest(TestEnvironment env, Result result) {
 482             Context ctx = new Context(env, result, TEST_IMAGEREADER);
 483             // override units since this test doesn't read "pixels"
 484             result.setUnits(1);
 485             result.setUnitName("image");
 486             return ctx;
 487         }
 488 
 489         public void runTest(Object ctx, int numReps) {
 490             final Context ictx = (Context)ctx;
 491             final ImageReader reader = ictx.reader;
 492             final boolean seekForwardOnly = ictx.seekForwardOnly;
 493             final boolean ignoreMetadata = ictx.ignoreMetadata;
 494             do {
 495                 try {
 496                     ImageInputStream iis = ictx.createImageInputStream();
 497                     reader.setInput(iis, seekForwardOnly, ignoreMetadata);
 498                     reader.getImageMetadata(0);
 499                     reader.reset();
 500                     iis.close();
 501                     ictx.closeOriginalStream();
 502                 } catch (IOException e) {
 503                     e.printStackTrace();
 504                 }
 505             } while (--numReps >= 0);
 506         }
 507     }
 508 
 509     private static class ReadProgressListener
 510         implements IIOReadProgressListener
 511     {
 512         public void sequenceStarted(ImageReader source, int minIndex) {}
 513         public void sequenceComplete(ImageReader source) {}
 514         public void imageStarted(ImageReader source, int imageIndex) {}
 515         public void imageProgress(ImageReader source, float percentageDone) {}
 516         public void imageComplete(ImageReader source) {}
 517         public void thumbnailStarted(ImageReader source,
 518                                      int imageIndex, int thumbnailIndex) {}
 519         public void thumbnailProgress(ImageReader source,
 520                                       float percentageDone) {}
 521         public void thumbnailComplete(ImageReader source) {}
 522         public void readAborted(ImageReader source) {}
 523     }
 524 }