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} 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} 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}. 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} this method will do nothing 93 * @param sInsets Insets specifying the portion of the image that will be stretched or tiled, if {@code null} 94 * empty {@code Insets} will be used. 95 * @param dInsets Destination insets specifying the portion of the image will be stretched or tiled, if 96 * {@code null} empty {@code Insets} 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} 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 }