1 /*
   2  * Copyright (c) 2005, 2006, 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 javax.swing.plaf.nimbus;
  26 
  27 import java.awt.Graphics;
  28 import java.awt.Image;
  29 import java.awt.Insets;
  30 
  31 /**
  32  * ImageScalingHelper
  33  *
  34  * @author Created by Jasper Potts (Aug 8, 2007)
  35  */
  36 class ImageScalingHelper {
  37 
  38     /** Enumeration for the types of painting this class can handle. */
  39     enum PaintType {
  40         /**
  41          * Painting type indicating the image should be centered in the space provided.  When used the <code>mask</code>
  42          * is ignored.
  43          */
  44         CENTER,
  45 
  46         /**
  47          * Painting type indicating the image should be tiled across the specified width and height.  When used the
  48          * <code>mask</code> is ignored.
  49          */
  50         TILE,
  51 
  52         /**
  53          * Painting type indicating the image should be split into nine regions with the top, left, bottom and right
  54          * areas stretched.
  55          */
  56         PAINT9_STRETCH,
  57 
  58         /**
  59          * Painting type indicating the image should be split into nine regions with the top, left, bottom and right
  60          * areas tiled.
  61          */
  62         PAINT9_TILE
  63     }
  64 
  65     ;
  66 
  67     private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0);
  68 
  69     static final int PAINT_TOP_LEFT = 1;
  70     static final int PAINT_TOP = 2;
  71     static final int PAINT_TOP_RIGHT = 4;
  72     static final int PAINT_LEFT = 8;
  73     static final int PAINT_CENTER = 16;
  74     static final int PAINT_RIGHT = 32;
  75     static final int PAINT_BOTTOM_RIGHT = 64;
  76     static final int PAINT_BOTTOM = 128;
  77     static final int PAINT_BOTTOM_LEFT = 256;
  78     /**
  79      * Specifies that all regions should be painted.  If this is set any other regions specified will not be painted.
  80      * For example PAINT_ALL | PAINT_CENTER will paint all but the center.
  81      */
  82     static final int PAINT_ALL = 512;
  83 
  84     /**
  85      * Paints using the algorightm specified by <code>paintType</code>.
  86      *
  87      * @param g         Graphics to render to
  88      * @param x         X-coordinate
  89      * @param y         Y-coordinate
  90      * @param w         Width to render to
  91      * @param h         Height to render to
  92      * @param image     Image to render from, if <code>null</code> this method will do nothing
  93      * @param sInsets   Insets specifying the portion of the image that will be stretched or tiled, if <code>null</code>
  94      *                  empty <code>Insets</code> will be used.
  95      * @param dInsets   Destination insets specifying the portion of the image will be stretched or tiled, if
  96      *                  <code>null</code> empty <code>Insets</code> will be used.
  97      * @param paintType Specifies what type of algorithm to use in painting
  98      * @param mask      Specifies portion of image to render, if <code>PAINT_ALL</code> is specified, any other regions
  99      *                  specified will not be painted, for example PAINT_ALL | PAINT_CENTER paints everything but the
 100      *                  center.
 101      */
 102     public static void paint(Graphics g, int x, int y, int w, int h,
 103                       Image image, Insets sInsets,
 104                       Insets dInsets, PaintType paintType, int mask) {
 105         if (image == null || image.getWidth(null) <= 0 || image.getHeight(null) <= 0) {
 106             return;
 107         }
 108         if (sInsets == null) {
 109             sInsets = EMPTY_INSETS;
 110         }
 111         if (dInsets == null) {
 112             dInsets = EMPTY_INSETS;
 113         }
 114         int iw = image.getWidth(null);
 115         int ih = image.getHeight(null);
 116 
 117         if (paintType == PaintType.CENTER) {
 118             // Center the image
 119             g.drawImage(image, x + (w - iw) / 2,
 120                     y + (h - ih) / 2, null);
 121         } else if (paintType == PaintType.TILE) {
 122             // Tile the image
 123             int lastIY = 0;
 124             for (int yCounter = y, maxY = y + h; yCounter < maxY;
 125                  yCounter += (ih - lastIY), lastIY = 0) {
 126                 int lastIX = 0;
 127                 for (int xCounter = x, maxX = x + w; xCounter < maxX;
 128                      xCounter += (iw - lastIX), lastIX = 0) {
 129                     int dx2 = Math.min(maxX, xCounter + iw - lastIX);
 130                     int dy2 = Math.min(maxY, yCounter + ih - lastIY);
 131                     g.drawImage(image, xCounter, yCounter, dx2, dy2,
 132                             lastIX, lastIY, lastIX + dx2 - xCounter,
 133                             lastIY + dy2 - yCounter, null);
 134                 }
 135             }
 136         } else {
 137             int st = sInsets.top;
 138             int sl = sInsets.left;
 139             int sb = sInsets.bottom;
 140             int sr = sInsets.right;
 141 
 142             int dt = dInsets.top;
 143             int dl = dInsets.left;
 144             int db = dInsets.bottom;
 145             int dr = dInsets.right;
 146 
 147             // Constrain the insets to the size of the image
 148             if (st + sb > ih) {
 149                 db = dt = sb = st = Math.max(0, ih / 2);
 150             }
 151             if (sl + sr > iw) {
 152                 dl = dr = sl = sr = Math.max(0, iw / 2);
 153             }
 154 
 155             // Constrain the insets to the size of the region we're painting
 156             // in.
 157             if (dt + db > h) {
 158                 dt = db = Math.max(0, h / 2 - 1);
 159             }
 160             if (dl + dr > w) {
 161                 dl = dr = Math.max(0, w / 2 - 1);
 162             }
 163 
 164             boolean stretch = (paintType == PaintType.PAINT9_STRETCH);
 165             if ((mask & PAINT_ALL) != 0) {
 166                 mask = (PAINT_ALL - 1) & ~mask;
 167             }
 168 
 169             if ((mask & PAINT_LEFT) != 0) {
 170                 drawChunk(image, g, stretch, x, y + dt, x + dl, y + h - db,
 171                         0, st, sl, ih - sb, false);
 172             }
 173             if ((mask & PAINT_TOP_LEFT) != 0) {
 174                 drawImage(image, g, x, y, x + dl, y + dt,
 175                         0, 0, sl, st);
 176             }
 177             if ((mask & PAINT_TOP) != 0) {
 178                 drawChunk(image, g, stretch, x + dl, y, x + w - dr, y + dt,
 179                         sl, 0, iw - sr, st, true);
 180             }
 181             if ((mask & PAINT_TOP_RIGHT) != 0) {
 182                 drawImage(image, g, x + w - dr, y, x + w, y + dt,
 183                         iw - sr, 0, iw, st);
 184             }
 185             if ((mask & PAINT_RIGHT) != 0) {
 186                 drawChunk(image, g, stretch,
 187                         x + w - dr, y + dt, x + w, y + h - db,
 188                         iw - sr, st, iw, ih - sb, false);
 189             }
 190             if ((mask & PAINT_BOTTOM_RIGHT) != 0) {
 191                 drawImage(image, g, x + w - dr, y + h - db, x + w, y + h,
 192                         iw - sr, ih - sb, iw, ih);
 193             }
 194             if ((mask & PAINT_BOTTOM) != 0) {
 195                 drawChunk(image, g, stretch,
 196                         x + dl, y + h - db, x + w - dr, y + h,
 197                         sl, ih - sb, iw - sr, ih, true);
 198             }
 199             if ((mask & PAINT_BOTTOM_LEFT) != 0) {
 200                 drawImage(image, g, x, y + h - db, x + dl, y + h,
 201                         0, ih - sb, sl, ih);
 202             }
 203             if ((mask & PAINT_CENTER) != 0) {
 204                 drawImage(image, g, x + dl, y + dt, x + w - dr, y + h - db,
 205                         sl, st, iw - sr, ih - sb);
 206             }
 207         }
 208     }
 209 
 210     /**
 211      * Draws a portion of an image, stretched or tiled.
 212      *
 213      * @param image Image to render.
 214      * @param g Graphics to render to
 215      * @param stretch Whether the image should be stretched or timed in the
 216      *                provided space.
 217      * @param dx1 X origin to draw to
 218      * @param dy1 Y origin to draw to
 219      * @param dx2 End x location to draw to
 220      * @param dy2 End y location to draw to
 221      * @param sx1 X origin to draw from
 222      * @param sy1 Y origin to draw from
 223      * @param sx2 Max x location to draw from
 224      * @param sy2 Max y location to draw from
 225      * @param xDirection Used if the image is not stretched. If true it
 226      *        indicates the image should be tiled along the x axis.
 227      */
 228     private static void drawChunk(Image image, Graphics g, boolean stretch,
 229                            int dx1, int dy1, int dx2, int dy2, int sx1,
 230                            int sy1, int sx2, int sy2,
 231                            boolean xDirection) {
 232         if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 ||
 233                               sy2 - sy1 <= 0) {
 234             // Bogus location, nothing to paint
 235             return;
 236         }
 237         if (stretch) {
 238             g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
 239         }
 240         else {
 241             int xSize = sx2 - sx1;
 242             int ySize = sy2 - sy1;
 243             int deltaX;
 244             int deltaY;
 245 
 246             if (xDirection) {
 247                 deltaX = xSize;
 248                 deltaY = 0;
 249             }
 250             else {
 251                 deltaX = 0;
 252                 deltaY = ySize;
 253             }
 254             while (dx1 < dx2 && dy1 < dy2) {
 255                 int newDX2 = Math.min(dx2, dx1 + xSize);
 256                 int newDY2 = Math.min(dy2, dy1 + ySize);
 257 
 258                 g.drawImage(image, dx1, dy1, newDX2, newDY2,
 259                             sx1, sy1, sx1 + newDX2 - dx1,
 260                             sy1 + newDY2 - dy1, null);
 261                 dx1 += deltaX;
 262                 dy1 += deltaY;
 263             }
 264         }
 265     }
 266 
 267     private static void drawImage(Image image, Graphics g,
 268                            int dx1, int dy1, int dx2, int dy2, int sx1,
 269                            int sy1, int sx2, int sy2) {
 270         // PENDING: is this necessary, will G2D do it for me?
 271         if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0 || sx2 - sx1 <= 0 ||
 272                 sy2 - sy1 <= 0) {
 273             // Bogus location, nothing to paint
 274             return;
 275         }
 276         g.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null);
 277     }
 278 
 279 
 280 }
--- EOF ---