1796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta/* 2796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 3796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 4796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * you may not use this file except in compliance with the License. 6796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * You may obtain a copy of the License at 7796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 8796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 10796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * See the License for the specific language governing permissions and 14796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * limitations under the License. 15796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 16796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 17796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptapackage android.view; 18796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 19476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull; 20796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 21796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.awt.Graphics2D; 22796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.awt.Image; 23796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.awt.image.BufferedImage; 24796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.awt.image.DataBufferInt; 25796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.io.IOException; 26796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport java.io.InputStream; 27796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 28796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptaimport javax.imageio.ImageIO; 29796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 30796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Guptapublic class ShadowPainter { 31796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 32796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 33796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Adds a drop shadow to a semi-transparent image (of an arbitrary shape) and returns it as a 34796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * new image. This method attempts to mimic the same visual characteristics as the rectangular 35796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)} 36796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}. 37635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * <p/> 38635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * If shadowSize is less or equals to 1, no shadow will be painted and the source image will be 39635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * returned instead. 40796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 41796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param source the source image 42796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link 43796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * #SMALL_SHADOW_SIZE}} 44796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 45635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * @return an image with the shadow painted in or the source image if shadowSize <= 1 46796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 47796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta @NonNull 48796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static BufferedImage createDropShadow(BufferedImage source, int shadowSize) { 49796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta shadowSize /= 2; // make shadow size have the same meaning as in the other shadow paint methods in this class 50796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 51796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return createDropShadow(source, shadowSize, 0.7f, 0); 52796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 53796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 54796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 55796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Creates a drop shadow of a given image and returns a new image which shows the input image on 56796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * top of its drop shadow. 57796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * <p/> 58796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * <b>NOTE: If the shape is rectangular and opaque, consider using {@link 59796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * #drawRectangleShadow(Graphics2D, int, int, int, int)} instead.</b> 60796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 61796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param source the source image to be shadowed 62796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param shadowSize the size of the shadow in pixels 63796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque 64796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param shadowRgb the RGB int to use for the shadow color 65796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 66635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * @return a new image with the source image on top of its shadow when shadowSize > 0 or the 67635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez * source image otherwise 68796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 69796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"}) // Imported code 70796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static BufferedImage createDropShadow(BufferedImage source, int shadowSize, 71796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta float shadowOpacity, int shadowRgb) { 72635d8f4fe771a0bb2771b23991f7ca758861b884Diego Perez if (shadowSize <= 0) { 73e81096458f689ab3c0c4dbab2452722c3e3623c4Diego Perez return source; 74e81096458f689ab3c0c4dbab2452722c3e3623c4Diego Perez } 75796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 76796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // This code is based on 77796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // http://www.jroller.com/gfx/entry/non_rectangular_shadow 78796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 79796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta BufferedImage image; 80796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int width = source.getWidth(); 81796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int height = source.getHeight(); 82796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, 83796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta BufferedImage.TYPE_INT_ARGB); 84796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 85796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta Graphics2D g2 = image.createGraphics(); 86796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g2.drawImage(image, shadowSize, shadowSize, null); 87796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 88796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int dstWidth = image.getWidth(); 89796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int dstHeight = image.getHeight(); 90796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 91796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int left = (shadowSize - 1) >> 1; 92796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int right = shadowSize - left; 93796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int xStart = left; 94796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int xStop = dstWidth - right; 95796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int yStart = left; 96796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int yStop = dstHeight - right; 97796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 98796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta shadowRgb &= 0x00FFFFFF; 99796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 100796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int[] aHistory = new int[shadowSize]; 101796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int historyIdx; 102796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 103796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int aSum; 104796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 105796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); 106796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int lastPixelOffset = right * dstWidth; 107796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta float sumDivider = shadowOpacity / shadowSize; 108796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 109796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // horizontal pass 110796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) { 111796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum = 0; 112796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta historyIdx = 0; 113796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int x = 0; x < shadowSize; x++, bufferOffset++) { 114796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int a = dataBuffer[bufferOffset] >>> 24; 115796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aHistory[x] = a; 116796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum += a; 117796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 118796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 119796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta bufferOffset -= right; 120796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 121796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int x = xStart; x < xStop; x++, bufferOffset++) { 122796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int a = (int) (aSum * sumDivider); 123796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta dataBuffer[bufferOffset] = a << 24 | shadowRgb; 124796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 125796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // subtract the oldest pixel from the sum 126796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum -= aHistory[historyIdx]; 127796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 128796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // get the latest pixel 129796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta a = dataBuffer[bufferOffset + right] >>> 24; 130796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aHistory[historyIdx] = a; 131796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum += a; 132796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 133796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (++historyIdx >= shadowSize) { 134796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta historyIdx -= shadowSize; 135796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 136796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 137796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 138796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // vertical pass 139796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) { 140796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum = 0; 141796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta historyIdx = 0; 142796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) { 143796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int a = dataBuffer[bufferOffset] >>> 24; 144796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aHistory[y] = a; 145796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum += a; 146796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 147796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 148796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta bufferOffset -= lastPixelOffset; 149796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 150796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) { 151796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int a = (int) (aSum * sumDivider); 152796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta dataBuffer[bufferOffset] = a << 24 | shadowRgb; 153796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 154796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // subtract the oldest pixel from the sum 155796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum -= aHistory[historyIdx]; 156796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 157796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // get the latest pixel 158796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24; 159796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aHistory[historyIdx] = a; 160796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta aSum += a; 161796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 162796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (++historyIdx >= shadowSize) { 163796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta historyIdx -= shadowSize; 164796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 165796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 166796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 167796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 168796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g2.drawImage(source, null, 0, 0); 169796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g2.dispose(); 170796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 171796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return image; 172796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 173796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 174796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 175796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a rectangular drop shadow (of size {@link #SHADOW_SIZE} by {@link #SHADOW_SIZE} around 176796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * the given source and returns a new image with both combined 177796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 178796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param source the source image 179796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 180796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @return the source image with a drop shadow on the bottom and right 181796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 182796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta @SuppressWarnings("UnusedDeclaration") 183796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static BufferedImage createRectangularDropShadow(BufferedImage source) { 184796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int type = source.getType(); 185796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (type == BufferedImage.TYPE_CUSTOM) { 186796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta type = BufferedImage.TYPE_INT_ARGB; 187796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 188796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 189796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int width = source.getWidth(); 190796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int height = source.getHeight(); 191796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta BufferedImage image; 192796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, type); 193796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta Graphics2D g = image.createGraphics(); 194796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g.drawImage(source, 0, 0, null); 195796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta drawRectangleShadow(image, 0, 0, width, height); 196796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g.dispose(); 197796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 198796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return image; 199796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 200796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 201796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 202796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a small rectangular drop shadow (of size {@link #SMALL_SHADOW_SIZE} by {@link 203796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * #SMALL_SHADOW_SIZE} around the given source and returns a new image with both combined 204796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 205796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param source the source image 206796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 207796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @return the source image with a drop shadow on the bottom and right 208796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 209796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta @SuppressWarnings("UnusedDeclaration") 210796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static BufferedImage createSmallRectangularDropShadow(BufferedImage source) { 211796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int type = source.getType(); 212796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (type == BufferedImage.TYPE_CUSTOM) { 213796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta type = BufferedImage.TYPE_INT_ARGB; 214796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 215796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 216796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int width = source.getWidth(); 217796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int height = source.getHeight(); 218796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 219796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta BufferedImage image; 220796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta image = new BufferedImage(width + SMALL_SHADOW_SIZE, height + SMALL_SHADOW_SIZE, type); 221796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 222796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta Graphics2D g = image.createGraphics(); 223796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g.drawImage(source, 0, 0, null); 224796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta drawSmallRectangleShadow(image, 0, 0, width, height); 225796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta g.dispose(); 226796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 227796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return image; 228796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 229796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 230796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 231796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a drop shadow for the given rectangle into the given context. It will not draw anything 232796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow 233796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * graphics. The size of the shadow is {@link #SHADOW_SIZE}. 234796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 235796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param image the image to draw the shadow into 236796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 237796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 238796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param width the width of the rectangle 239796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param height the height of the rectangle 240796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 241796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static void drawRectangleShadow(BufferedImage image, 242796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int x, int y, int width, int height) { 243796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta Graphics2D gc = image.createGraphics(); 244796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta try { 245796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta drawRectangleShadow(gc, x, y, width, height); 246796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } finally { 247796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.dispose(); 248796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 249796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 250796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 251796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 252796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a small drop shadow for the given rectangle into the given context. It will not draw 253796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * anything if the rectangle is smaller than a minimum determined by the assets used to draw the 254796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * shadow graphics. The size of the shadow is {@link #SMALL_SHADOW_SIZE}. 255796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 256796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param image the image to draw the shadow into 257796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 258796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 259796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param width the width of the rectangle 260796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param height the height of the rectangle 261796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 262796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static void drawSmallRectangleShadow(BufferedImage image, 263796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int x, int y, int width, int height) { 264796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta Graphics2D gc = image.createGraphics(); 265796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta try { 266796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta drawSmallRectangleShadow(gc, x, y, width, height); 267796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } finally { 268796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.dispose(); 269796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 270796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 271796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 272796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 273796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * The width and height of the drop shadow painted by 274796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * {@link #drawRectangleShadow(Graphics2D, int, int, int, int)} 275796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 276796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static final int SHADOW_SIZE = 20; // DO NOT EDIT. This corresponds to bitmap graphics 277796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 278796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 279796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * The width and height of the drop shadow painted by 280796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * {@link #drawSmallRectangleShadow(Graphics2D, int, int, int, int)} 281796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 282796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static final int SMALL_SHADOW_SIZE = 10; // DO NOT EDIT. Corresponds to bitmap graphics 283796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 284796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 285796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a drop shadow for the given rectangle into the given context. It will not draw anything 286796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow 287796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * graphics. 288796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 289796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param gc the graphics context to draw into 290796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 291796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 292796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param width the width of the rectangle 293796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param height the height of the rectangle 294796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 295796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static void drawRectangleShadow(Graphics2D gc, int x, int y, int width, int height) { 296796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert ShadowBottomLeft != null; 297796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert ShadowBottomRight.getWidth(null) == SHADOW_SIZE; 298796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert ShadowBottomRight.getHeight(null) == SHADOW_SIZE; 299796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 300796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int blWidth = ShadowBottomLeft.getWidth(null); 301796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int trHeight = ShadowTopRight.getHeight(null); 302796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (width < blWidth) { 303796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return; 304796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 305796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (height < trHeight) { 306796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return; 307796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 308796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 309796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowBottomLeft, x - ShadowBottomLeft.getWidth(null), y + height, null); 310796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowBottomRight, x + width, y + height, null); 311796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowTopRight, x + width, y, null); 312796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowTopLeft, x - ShadowTopLeft.getWidth(null), y, null); 313796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowBottom, 314796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x, y + height, x + width, y + height + ShadowBottom.getHeight(null), 315796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, ShadowBottom.getWidth(null), ShadowBottom.getHeight(null), null); 316796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowRight, 317796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x + width, y + ShadowTopRight.getHeight(null), x + width + ShadowRight.getWidth(null), y + height, 318796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, ShadowRight.getWidth(null), ShadowRight.getHeight(null), null); 319796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(ShadowLeft, 320796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x - ShadowLeft.getWidth(null), y + ShadowTopLeft.getHeight(null), x, y + height, 321796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, ShadowLeft.getWidth(null), ShadowLeft.getHeight(null), null); 322796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 323796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 324796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta /** 325796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * Draws a small drop shadow for the given rectangle into the given context. It will not draw 326796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * anything if the rectangle is smaller than a minimum determined by the assets used to draw the 327796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * shadow graphics. 328796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * <p/> 329796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * 330796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param gc the graphics context to draw into 331796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param x the left coordinate of the left hand side of the rectangle 332796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param y the top coordinate of the top of the rectangle 333796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param width the width of the rectangle 334796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta * @param height the height of the rectangle 335796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta */ 336796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta public static void drawSmallRectangleShadow(Graphics2D gc, int x, int y, int width, 337796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int height) { 338796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert Shadow2BottomLeft != null; 339796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert Shadow2TopRight != null; 340796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert Shadow2BottomRight.getWidth(null) == SMALL_SHADOW_SIZE; 341796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta assert Shadow2BottomRight.getHeight(null) == SMALL_SHADOW_SIZE; 342796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 343796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int blWidth = Shadow2BottomLeft.getWidth(null); 344796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta int trHeight = Shadow2TopRight.getHeight(null); 345796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (width < blWidth) { 346796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return; 347796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 348796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (height < trHeight) { 349796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return; 350796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 351796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 352796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2BottomLeft, x - Shadow2BottomLeft.getWidth(null), y + height, null); 353796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2BottomRight, x + width, y + height, null); 354796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2TopRight, x + width, y, null); 355796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2TopLeft, x - Shadow2TopLeft.getWidth(null), y, null); 356796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2Bottom, 357796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x, y + height, x + width, y + height + Shadow2Bottom.getHeight(null), 358796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, Shadow2Bottom.getWidth(null), Shadow2Bottom.getHeight(null), null); 359796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2Right, 360796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x + width, y + Shadow2TopRight.getHeight(null), x + width + Shadow2Right.getWidth(null), y + height, 361796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, Shadow2Right.getWidth(null), Shadow2Right.getHeight(null), null); 362796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta gc.drawImage(Shadow2Left, 363796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta x - Shadow2Left.getWidth(null), y + Shadow2TopLeft.getHeight(null), x, y + height, 364796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 0, 0, Shadow2Left.getWidth(null), Shadow2Left.getHeight(null), null); 365796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 366796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 367796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static Image loadIcon(String name) { 368796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta InputStream inputStream = ShadowPainter.class.getResourceAsStream(name); 369796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta if (inputStream == null) { 370796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta throw new RuntimeException("Unable to load image for shadow: " + name); 371796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 372796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta try { 373796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta return ImageIO.read(inputStream); 374796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } catch (IOException e) { 375796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta throw new RuntimeException("Unable to load image for shadow:" + name, e); 376796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } finally { 377796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta try { 378796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta inputStream.close(); 379796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } catch (IOException e) { 380796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // ignore. 381796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 382796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 383796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta } 384796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 385796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // Shadow graphics. This was generated by creating a drop shadow in 386796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // Gimp, using the parameters x offset=10, y offset=10, blur radius=10, 387796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // (for the small drop shadows x offset=10, y offset=10, blur radius=10) 388796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // color=black, and opacity=51. These values attempt to make a shadow 389796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // that is legible both for dark and light themes, on top of the 390796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // canvas background (rgb(150,150,150). Darker shadows would tend to 391796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // blend into the foreground for a dark holo screen, and lighter shadows 392796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // would be hard to spot on the canvas background. If you make adjustments, 393796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // make sure to check the shadow with both dark and light themes. 394796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // 395796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // After making the graphics, I cut out the top right, bottom left 396796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // and bottom right corners as 20x20 images, and these are reproduced by 397796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // painting them in the corresponding places in the target graphics context. 398796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // I then grabbed a single horizontal gradient line from the middle of the 399796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // right edge,and a single vertical gradient line from the bottom. These 400796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // are then painted scaled/stretched in the target to fill the gaps between 401796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // the three corner images. 402796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // 403796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // Filenames: bl=bottom left, b=bottom, br=bottom right, r=right, tr=top right 404796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 405796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // Normal Drop Shadow 406796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowBottom = loadIcon("/icons/shadow-b.png"); 407796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowBottomLeft = loadIcon("/icons/shadow-bl.png"); 408796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowBottomRight = loadIcon("/icons/shadow-br.png"); 409796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowRight = loadIcon("/icons/shadow-r.png"); 410796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowTopRight = loadIcon("/icons/shadow-tr.png"); 411796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowTopLeft = loadIcon("/icons/shadow-tl.png"); 412796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image ShadowLeft = loadIcon("/icons/shadow-l.png"); 413796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta 414796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta // Small Drop Shadow 415796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2Bottom = loadIcon("/icons/shadow2-b.png"); 416796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2BottomLeft = loadIcon("/icons/shadow2-bl.png"); 417796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2BottomRight = loadIcon("/icons/shadow2-br.png"); 418796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2Right = loadIcon("/icons/shadow2-r.png"); 419796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2TopRight = loadIcon("/icons/shadow2-tr.png"); 420796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2TopLeft = loadIcon("/icons/shadow2-tl.png"); 421796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta private static final Image Shadow2Left = loadIcon("/icons/shadow2-l.png"); 422796e9b7f9910f2ba8133cdb6f137107585b2e5faDeepanshu Gupta} 423