13d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta/* 23d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 33d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 43d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 53d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * you may not use this file except in compliance with the License. 63d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * You may obtain a copy of the License at 73d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 83d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 93d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software 113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * See the License for the specific language governing permissions and 143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * limitations under the License. 153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptapackage android.view; 183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 19442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull; 203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.Graphics2D; 223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.Image; 233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.image.BufferedImage; 243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.awt.image.DataBufferInt; 253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.io.IOException; 263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport java.io.InputStream; 273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptaimport javax.imageio.ImageIO; 293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Guptapublic class ShadowPainter { 313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Adds a drop shadow to a semi-transparent image (of an arbitrary shape) and returns it as a 343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * new image. This method attempts to mimic the same visual characteristics as the rectangular 353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)} 363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}. 371245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * <p/> 381245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * If shadowSize is less or equals to 1, no shadow will be painted and the source image will be 391245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * returned instead. 403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param source the source image 423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link 433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * #SMALL_SHADOW_SIZE}} 443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 451245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * @return an image with the shadow painted in or the source image if shadowSize <= 1 463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta @NonNull 483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static BufferedImage createDropShadow(BufferedImage source, int shadowSize) { 493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta shadowSize /= 2; // make shadow size have the same meaning as in the other shadow paint methods in this class 503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return createDropShadow(source, shadowSize, 0.7f, 0); 523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Creates a drop shadow of a given image and returns a new image which shows the input image on 563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * top of its drop shadow. 573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * <p/> 583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * <b>NOTE: If the shape is rectangular and opaque, consider using {@link 593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * #drawRectangleShadow(Graphics2D, int, int, int, int)} instead.</b> 603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param source the source image to be shadowed 623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param shadowSize the size of the shadow in pixels 633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque 643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param shadowRgb the RGB int to use for the shadow color 653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 661245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * @return a new image with the source image on top of its shadow when shadowSize > 0 or the 671245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez * source image otherwise 683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"}) // Imported code 703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static BufferedImage createDropShadow(BufferedImage source, int shadowSize, 713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta float shadowOpacity, int shadowRgb) { 721245caa7fd9c5cbf21fe5f5effe317dfbebc064aDiego Perez if (shadowSize <= 0) { 733c8e871ab7811a05cf5fc3debe798e342dc19ee9Diego Perez return source; 743c8e871ab7811a05cf5fc3debe798e342dc19ee9Diego Perez } 753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // This code is based on 773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // http://www.jroller.com/gfx/entry/non_rectangular_shadow 783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta BufferedImage image; 803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int width = source.getWidth(); 813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int height = source.getHeight(); 823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, 833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta BufferedImage.TYPE_INT_ARGB); 843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta Graphics2D g2 = image.createGraphics(); 863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g2.drawImage(image, shadowSize, shadowSize, null); 873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int dstWidth = image.getWidth(); 893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int dstHeight = image.getHeight(); 903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int left = (shadowSize - 1) >> 1; 923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int right = shadowSize - left; 933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int xStart = left; 943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int xStop = dstWidth - right; 953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int yStart = left; 963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int yStop = dstHeight - right; 973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta shadowRgb &= 0x00FFFFFF; 993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int[] aHistory = new int[shadowSize]; 1013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int historyIdx; 1023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int aSum; 1043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); 1063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int lastPixelOffset = right * dstWidth; 1073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta float sumDivider = shadowOpacity / shadowSize; 1083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // horizontal pass 1103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) { 1113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum = 0; 1123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta historyIdx = 0; 1133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int x = 0; x < shadowSize; x++, bufferOffset++) { 1143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int a = dataBuffer[bufferOffset] >>> 24; 1153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aHistory[x] = a; 1163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum += a; 1173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta bufferOffset -= right; 1203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int x = xStart; x < xStop; x++, bufferOffset++) { 1223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int a = (int) (aSum * sumDivider); 1233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta dataBuffer[bufferOffset] = a << 24 | shadowRgb; 1243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // subtract the oldest pixel from the sum 1263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum -= aHistory[historyIdx]; 1273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // get the latest pixel 1293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta a = dataBuffer[bufferOffset + right] >>> 24; 1303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aHistory[historyIdx] = a; 1313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum += a; 1323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (++historyIdx >= shadowSize) { 1343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta historyIdx -= shadowSize; 1353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // vertical pass 1393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) { 1403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum = 0; 1413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta historyIdx = 0; 1423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) { 1433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int a = dataBuffer[bufferOffset] >>> 24; 1443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aHistory[y] = a; 1453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum += a; 1463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta bufferOffset -= lastPixelOffset; 1493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) { 1513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int a = (int) (aSum * sumDivider); 1523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta dataBuffer[bufferOffset] = a << 24 | shadowRgb; 1533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // subtract the oldest pixel from the sum 1553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum -= aHistory[historyIdx]; 1563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // get the latest pixel 1583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24; 1593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aHistory[historyIdx] = a; 1603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta aSum += a; 1613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (++historyIdx >= shadowSize) { 1633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta historyIdx -= shadowSize; 1643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g2.drawImage(source, null, 0, 0); 1693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g2.dispose(); 1703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return image; 1723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 1753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a rectangular drop shadow (of size {@link #SHADOW_SIZE} by {@link #SHADOW_SIZE} around 1763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * the given source and returns a new image with both combined 1773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 1783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param source the source image 1793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 1803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @return the source image with a drop shadow on the bottom and right 1813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 1823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta @SuppressWarnings("UnusedDeclaration") 1833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static BufferedImage createRectangularDropShadow(BufferedImage source) { 1843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int type = source.getType(); 1853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (type == BufferedImage.TYPE_CUSTOM) { 1863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta type = BufferedImage.TYPE_INT_ARGB; 1873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 1883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int width = source.getWidth(); 1903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int height = source.getHeight(); 1913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta BufferedImage image; 1923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, type); 1933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta Graphics2D g = image.createGraphics(); 1943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g.drawImage(source, 0, 0, null); 1953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta drawRectangleShadow(image, 0, 0, width, height); 1963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g.dispose(); 1973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 1983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return image; 1993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a small rectangular drop shadow (of size {@link #SMALL_SHADOW_SIZE} by {@link 2033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * #SMALL_SHADOW_SIZE} around the given source and returns a new image with both combined 2043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 2053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param source the source image 2063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 2073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @return the source image with a drop shadow on the bottom and right 2083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta @SuppressWarnings("UnusedDeclaration") 2103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static BufferedImage createSmallRectangularDropShadow(BufferedImage source) { 2113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int type = source.getType(); 2123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (type == BufferedImage.TYPE_CUSTOM) { 2133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta type = BufferedImage.TYPE_INT_ARGB; 2143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int width = source.getWidth(); 2173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int height = source.getHeight(); 2183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta BufferedImage image; 2203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta image = new BufferedImage(width + SMALL_SHADOW_SIZE, height + SMALL_SHADOW_SIZE, type); 2213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta Graphics2D g = image.createGraphics(); 2233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g.drawImage(source, 0, 0, null); 2243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta drawSmallRectangleShadow(image, 0, 0, width, height); 2253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta g.dispose(); 2263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return image; 2283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a drop shadow for the given rectangle into the given context. It will not draw anything 2323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow 2333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * graphics. The size of the shadow is {@link #SHADOW_SIZE}. 2343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 2353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param image the image to draw the shadow into 2363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 2373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 2383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param width the width of the rectangle 2393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param height the height of the rectangle 2403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static void drawRectangleShadow(BufferedImage image, 2423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int x, int y, int width, int height) { 2433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta Graphics2D gc = image.createGraphics(); 2443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta try { 2453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta drawRectangleShadow(gc, x, y, width, height); 2463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } finally { 2473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.dispose(); 2483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a small drop shadow for the given rectangle into the given context. It will not draw 2533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * anything if the rectangle is smaller than a minimum determined by the assets used to draw the 2543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * shadow graphics. The size of the shadow is {@link #SMALL_SHADOW_SIZE}. 2553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 2563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param image the image to draw the shadow into 2573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 2583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 2593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param width the width of the rectangle 2603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param height the height of the rectangle 2613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static void drawSmallRectangleShadow(BufferedImage image, 2633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int x, int y, int width, int height) { 2643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta Graphics2D gc = image.createGraphics(); 2653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta try { 2663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta drawSmallRectangleShadow(gc, x, y, width, height); 2673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } finally { 2683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.dispose(); 2693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 2713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * The width and height of the drop shadow painted by 2743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * {@link #drawRectangleShadow(Graphics2D, int, int, int, int)} 2753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static final int SHADOW_SIZE = 20; // DO NOT EDIT. This corresponds to bitmap graphics 2773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * The width and height of the drop shadow painted by 2803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * {@link #drawSmallRectangleShadow(Graphics2D, int, int, int, int)} 2813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static final int SMALL_SHADOW_SIZE = 10; // DO NOT EDIT. Corresponds to bitmap graphics 2833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 2843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 2853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a drop shadow for the given rectangle into the given context. It will not draw anything 2863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow 2873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * graphics. 2883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 2893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param gc the graphics context to draw into 2903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 2913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 2923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param width the width of the rectangle 2933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param height the height of the rectangle 2943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 2953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static void drawRectangleShadow(Graphics2D gc, int x, int y, int width, int height) { 2963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert ShadowBottomLeft != null; 2973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert ShadowBottomRight.getWidth(null) == SHADOW_SIZE; 2983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert ShadowBottomRight.getHeight(null) == SHADOW_SIZE; 2993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int blWidth = ShadowBottomLeft.getWidth(null); 3013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int trHeight = ShadowTopRight.getHeight(null); 3023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (width < blWidth) { 3033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return; 3043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (height < trHeight) { 3063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return; 3073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowBottomLeft, x - ShadowBottomLeft.getWidth(null), y + height, null); 3103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowBottomRight, x + width, y + height, null); 3113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowTopRight, x + width, y, null); 3123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowTopLeft, x - ShadowTopLeft.getWidth(null), y, null); 3133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowBottom, 3143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x, y + height, x + width, y + height + ShadowBottom.getHeight(null), 3153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, ShadowBottom.getWidth(null), ShadowBottom.getHeight(null), null); 3163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowRight, 3173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x + width, y + ShadowTopRight.getHeight(null), x + width + ShadowRight.getWidth(null), y + height, 3183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, ShadowRight.getWidth(null), ShadowRight.getHeight(null), null); 3193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(ShadowLeft, 3203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x - ShadowLeft.getWidth(null), y + ShadowTopLeft.getHeight(null), x, y + height, 3213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, ShadowLeft.getWidth(null), ShadowLeft.getHeight(null), null); 3223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3233d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3243d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta /** 3253d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * Draws a small drop shadow for the given rectangle into the given context. It will not draw 3263d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * anything if the rectangle is smaller than a minimum determined by the assets used to draw the 3273d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * shadow graphics. 3283d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * <p/> 3293d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * 3303d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param gc the graphics context to draw into 3313d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 3323d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 3333d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param width the width of the rectangle 3343d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta * @param height the height of the rectangle 3353d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta */ 3363d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta public static void drawSmallRectangleShadow(Graphics2D gc, int x, int y, int width, 3373d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int height) { 3383d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert Shadow2BottomLeft != null; 3393d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert Shadow2TopRight != null; 3403d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert Shadow2BottomRight.getWidth(null) == SMALL_SHADOW_SIZE; 3413d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta assert Shadow2BottomRight.getHeight(null) == SMALL_SHADOW_SIZE; 3423d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3433d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int blWidth = Shadow2BottomLeft.getWidth(null); 3443d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta int trHeight = Shadow2TopRight.getHeight(null); 3453d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (width < blWidth) { 3463d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return; 3473d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3483d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (height < trHeight) { 3493d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return; 3503d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3513d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3523d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2BottomLeft, x - Shadow2BottomLeft.getWidth(null), y + height, null); 3533d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2BottomRight, x + width, y + height, null); 3543d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2TopRight, x + width, y, null); 3553d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2TopLeft, x - Shadow2TopLeft.getWidth(null), y, null); 3563d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2Bottom, 3573d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x, y + height, x + width, y + height + Shadow2Bottom.getHeight(null), 3583d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, Shadow2Bottom.getWidth(null), Shadow2Bottom.getHeight(null), null); 3593d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2Right, 3603d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x + width, y + Shadow2TopRight.getHeight(null), x + width + Shadow2Right.getWidth(null), y + height, 3613d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, Shadow2Right.getWidth(null), Shadow2Right.getHeight(null), null); 3623d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta gc.drawImage(Shadow2Left, 3633d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta x - Shadow2Left.getWidth(null), y + Shadow2TopLeft.getHeight(null), x, y + height, 3643d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 0, 0, Shadow2Left.getWidth(null), Shadow2Left.getHeight(null), null); 3653d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3663d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3673d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static Image loadIcon(String name) { 3683d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta InputStream inputStream = ShadowPainter.class.getResourceAsStream(name); 3693d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta if (inputStream == null) { 3703d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta throw new RuntimeException("Unable to load image for shadow: " + name); 3713d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3723d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta try { 3733d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta return ImageIO.read(inputStream); 3743d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } catch (IOException e) { 3753d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta throw new RuntimeException("Unable to load image for shadow:" + name, e); 3763d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } finally { 3773d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta try { 3783d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta inputStream.close(); 3793d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } catch (IOException e) { 3803d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // ignore. 3813d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3823d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3833d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta } 3843d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 3853d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // Shadow graphics. This was generated by creating a drop shadow in 3863d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // Gimp, using the parameters x offset=10, y offset=10, blur radius=10, 3873d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // (for the small drop shadows x offset=10, y offset=10, blur radius=10) 3883d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // color=black, and opacity=51. These values attempt to make a shadow 3893d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // that is legible both for dark and light themes, on top of the 3903d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // canvas background (rgb(150,150,150). Darker shadows would tend to 3913d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // blend into the foreground for a dark holo screen, and lighter shadows 3923d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // would be hard to spot on the canvas background. If you make adjustments, 3933d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // make sure to check the shadow with both dark and light themes. 3943d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // 3953d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // After making the graphics, I cut out the top right, bottom left 3963d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // and bottom right corners as 20x20 images, and these are reproduced by 3973d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // painting them in the corresponding places in the target graphics context. 3983d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // I then grabbed a single horizontal gradient line from the middle of the 3993d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // right edge,and a single vertical gradient line from the bottom. These 4003d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // are then painted scaled/stretched in the target to fill the gaps between 4013d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // the three corner images. 4023d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // 4033d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // Filenames: bl=bottom left, b=bottom, br=bottom right, r=right, tr=top right 4043d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 4053d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // Normal Drop Shadow 4063d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowBottom = loadIcon("/icons/shadow-b.png"); 4073d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowBottomLeft = loadIcon("/icons/shadow-bl.png"); 4083d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowBottomRight = loadIcon("/icons/shadow-br.png"); 4093d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowRight = loadIcon("/icons/shadow-r.png"); 4103d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowTopRight = loadIcon("/icons/shadow-tr.png"); 4113d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowTopLeft = loadIcon("/icons/shadow-tl.png"); 4123d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image ShadowLeft = loadIcon("/icons/shadow-l.png"); 4133d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta 4143d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta // Small Drop Shadow 4153d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2Bottom = loadIcon("/icons/shadow2-b.png"); 4163d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2BottomLeft = loadIcon("/icons/shadow2-bl.png"); 4173d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2BottomRight = loadIcon("/icons/shadow2-br.png"); 4183d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2Right = loadIcon("/icons/shadow2-r.png"); 4193d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2TopRight = loadIcon("/icons/shadow2-tr.png"); 4203d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2TopLeft = loadIcon("/icons/shadow2-tl.png"); 4213d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta private static final Image Shadow2Left = loadIcon("/icons/shadow2-l.png"); 4223d65b9279686974dc4cf8351efda9cd59ba59cbdDeepanshu Gupta} 423