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