1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.awt.image;
  26 
  27 import java.awt.Image;
  28 import java.util.List;
  29 import java.util.Arrays;
  30 import java.util.Collections;
  31 import java.util.Objects;
  32 
  33 /**
  34  * This class is an array-based implementation of
  35  * the {@code AbstractMultiResolutionImage} class.
  36  *
  37  * This class will implement the
  38  * {@code getResolutionVariant(double destImageWidth, double destImageHeight)}
  39  * method using a simple algorithm which will return the first image variant
  40  * in the array that is large enough to satisfy the rendering request. The
  41  * last image in the array will be returned if no suitable image is found
  42  * that is as large as the rendering request.
  43  * <p>
  44  * For best effect the array of images should be sorted with each image being
  45  * both wider and taller than the previous image.  The base image need not be
  46  * the first image in the array. No exception will be thrown if the images
  47  * are not sorted as suggested.
  48  *
  49  * @see java.awt.Image
  50  * @see java.awt.image.MultiResolutionImage
  51  * @see java.awt.image.AbstractMultiResolutionImage
  52  *
  53  * @since 1.9
  54  */
  55 public class BaseMultiResolutionImage extends AbstractMultiResolutionImage {
  56 
  57     private final int baseImageIndex;
  58     private final Image[] resolutionVariants;
  59 
  60     /**
  61      * Creates a multi-resolution image with the given resolution variants.
  62      * The first resolution variant is used as the base image.
  63      *
  64      * @param resolutionVariants array of resolution variants sorted by image size
  65      * @throws IllegalArgumentException if null or zero-length array is passed
  66      * @throws NullPointerException if the specified {@code resolutionVariants}
  67      *          contains one or more null elements
  68      *
  69      * @since 1.9
  70      */
  71     public BaseMultiResolutionImage(Image... resolutionVariants) {
  72         this(0, resolutionVariants);
  73     }
  74 
  75     /**
  76      * Creates a multi-resolution image with the given base image index and
  77      * resolution variants.
  78      *
  79      * @param baseImageIndex the index of base image in the resolution variants
  80      *        array
  81      * @param resolutionVariants array of resolution variants sorted by image size
  82      * @throws IllegalArgumentException if null or zero-length array is passed
  83      * @throws NullPointerException if the specified {@code resolutionVariants}
  84      *          contains one or more null elements
  85      * @throws IndexOutOfBoundsException if {@code baseImageIndex} is
  86      *          negative or greater than or equal to {@code resolutionVariants}
  87      *          length.
  88      *
  89      * @since 1.9
  90      */
  91     public BaseMultiResolutionImage(int baseImageIndex,
  92                                     Image... resolutionVariants) {
  93 
  94         if (resolutionVariants == null || resolutionVariants.length == 0) {
  95             throw new IllegalArgumentException(
  96                     "Null or zero-length array is passed");
  97         }
  98 
  99         if (baseImageIndex < 0 || baseImageIndex >= resolutionVariants.length) {
 100             throw new IndexOutOfBoundsException("Invalid base image index: "
 101                     + baseImageIndex);
 102         }
 103 
 104         this.baseImageIndex = baseImageIndex;
 105         this.resolutionVariants = Arrays.copyOf(resolutionVariants,
 106                                                 resolutionVariants.length);
 107 
 108         for (Image resolutionVariant : this.resolutionVariants) {
 109             Objects.requireNonNull(resolutionVariant,
 110                                    "Resolution variant can't be null");
 111         }
 112     }
 113 
 114     @Override
 115     public Image getResolutionVariant(double destImageWidth,
 116                                       double destImageHeight) {
 117 
 118         checkSize(destImageWidth, destImageHeight);
 119 
 120         for (Image rvImage : resolutionVariants) {
 121             if (destImageWidth <= rvImage.getWidth(null)
 122                     && destImageHeight <= rvImage.getHeight(null)) {
 123                 return rvImage;
 124             }
 125         }
 126         return resolutionVariants[resolutionVariants.length - 1];
 127     }
 128 
 129     private static void checkSize(double width, double height) {
 130         if (width <= 0 || height <= 0) {
 131             throw new IllegalArgumentException(String.format(
 132                     "Width (%s) or height (%s) cannot be <= 0", width, height));
 133         }
 134 
 135         if (!Double.isFinite(width) || !Double.isFinite(height)) {
 136             throw new IllegalArgumentException(String.format(
 137                     "Width (%s) or height (%s) is not finite", width, height));
 138         }
 139     }
 140 
 141     @Override
 142     public List<Image> getResolutionVariants() {
 143         return Collections.unmodifiableList(Arrays.asList(resolutionVariants));
 144     }
 145 
 146     @Override
 147     protected Image getBaseImage() {
 148         return resolutionVariants[baseImageIndex];
 149     }