Adds a shadow outside opaque or partial transparent shapes. - Java java.lang

Java examples for java.lang:Math Geometry Shape

Description

Adds a shadow outside opaque or partial transparent shapes.

Demo Code

/*//from w  ww  .  ja v a  2  s.  c  om
 *   Copyright (C) 2012 Markus Niedermann
 *   
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   any later version.
 *   
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *   
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
//package com.java2s;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;

public class Main {
    /**
     * Adds a shadow outside opaque or partial transparent shapes. AntiAliasing
     * is ON.
     * 
     * @param src
     *            source image
     * @param shadowColor
     *            color of the shadow
     * @param distance
     *            distance between shadow and shape
     * @param shadowRadius
     *            blur radius for the shadow
     * @param lift
     *            true, if shape should be placed higher than in the original
     *            shape, false if shadow should be placed lower
     * @return
     */
    public static BufferedImage addShadow(final BufferedImage src,
            final Color shadowColor, final int distance,
            final int shadowRadius, final boolean lift) {
        return addShadow(src, shadowColor, distance, shadowRadius, 0, true,
                lift);
    }

    /**
     * Adds a shadow outside opaque or partial transparent shapes.
     * 
     * @param src
     *            source image
     * @param shadowColor
     *            color of the shadow
     * @param distance
     *            distance between shadow and shape
     * @param shadowRadius
     *            blur radius for the shadow
     * @param opaqueLimit
     *            sets the opacity limit. range: 0-255
     * 
     * @param useAntiAliasing
     *            true, if anti aliasing should be used.
     * @param lift
     *            true, if shape should be placed higher than in the original
     *            shape, false if shadow should be placed lower
     * @return
     */
    public static BufferedImage addShadow(final BufferedImage src,
            final Color shadowColor, final int distance,
            final int shadowRadius, final int opaqueLimit,
            final boolean useAntiAliasing, final boolean lift) {

        BufferedImage ret = new BufferedImage(src.getWidth(),
                src.getHeight(), BufferedImage.TYPE_INT_ARGB);

        BufferedImage opaque = smaller(
                getOpaqueImage(src, shadowColor, opaqueLimit),
                shadowRadius / 2, opaqueLimit);
        BufferedImage border = getGlow(opaque, shadowColor, shadowRadius,
                opaqueLimit, useAntiAliasing);

        Graphics2D g2d = (Graphics2D) ret.getGraphics();
        int x1 = lift ? -distance : 0;
        int x0 = lift ? 0 : distance;
        int y1 = lift ? -distance : 0;
        int y0 = lift ? 0 : distance;

        g2d.drawImage(opaque, x0, y0, null);

        g2d.drawImage(border, x0, y0, null);
        g2d.drawImage(src, x1, y1, null);

        return ret;
    }

    private static BufferedImage smaller(final BufferedImage src,
            final int radius, final int opaqueLimit) {

        BufferedImage ret = new BufferedImage(src.getWidth(),
                src.getHeight(), BufferedImage.TYPE_INT_ARGB);
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                if (((src.getRGB(x, y) >> 24) & 0xff) > opaqueLimit
                        && checkRadius(src, x, y, opaqueLimit, radius)) {
                    ret.setRGB(x, y, src.getRGB(x, y));
                }

            }
        }
        return ret;
    }

    private static BufferedImage getOpaqueImage(final BufferedImage src,
            final Color col, final int opaqueLimit) {
        BufferedImage ret = new BufferedImage(src.getWidth(),
                src.getHeight(), BufferedImage.TYPE_INT_ARGB);
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                if (((src.getRGB(x, y) >> 24) & 0xff) > opaqueLimit) {
                    ret.setRGB(x, y, col.getRGB());
                }

            }
        }
        return ret;
    }

    /**
     * 
     * Returns a Glow outside opaque or partial transparent shapes.
     * 
     * @param src
     *            source image
     * @param glowColor
     *            color of the glow
     * @param radius
     *            radius of the glow
     * @param opaqueLimit
     *            sets the opacity limit. range: 0-255
     * @param useAntiAliasing
     *            true, if anti aliasing should be used.
     * @return new BufferedImage, containing glow
     */
    public static BufferedImage getGlow(final BufferedImage src,
            final Color glowColor, final int radius, final int opaqueLimit,
            final boolean useAntiAliasing) {
        BufferedImage ret = new BufferedImage(src.getWidth(),
                src.getHeight(), BufferedImage.TYPE_INT_ARGB);
        return getGlow(src, glowColor, radius, opaqueLimit,
                useAntiAliasing, ret);

    }

    private static BufferedImage getGlow(final BufferedImage src,
            final Color glowColor, final int radius, final int opaqueLimit,
            final boolean useAntiAliasing, final BufferedImage ret) {

        boolean[][] opaque = getOpaqueMask(src, opaqueLimit);
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                if (((src.getRGB(x, y) >> 24) & 0xff) > opaqueLimit) {
                    if (isBorder(x, y, src, opaqueLimit)) {
                        addGlow(ret, x, y, radius, glowColor.getRGB(),
                                opaque);
                    }
                }

            }
        }

        if (useAntiAliasing) {
            setRenderHints(ret);
        }

        return ret;

    }

    private static boolean checkRadius(final BufferedImage src,
            final int x, final int y, final int opaqueLimit,
            final int radius) {
        int minX = Math.max(x - radius, 0);
        int maxX = Math.min(src.getWidth(), x + radius);

        int minY = Math.max(y - radius, 0);
        int maxY = Math.min(src.getHeight(), y + radius);

        for (int curY = minY; curY < maxY; curY++) {
            for (int curX = minX; curX < maxX; curX++) {
                if (getDistance(curX, curY, x, y, radius) <= 1
                        && ((src.getRGB(curX, curY) >> 24) & 0xff) <= opaqueLimit) {
                    return false;
                }
            }
        }
        return true;
    }

    private static boolean[][] getOpaqueMask(final BufferedImage src,
            final int opaqueLimit) {
        boolean[][] opaque = new boolean[src.getHeight()][src.getWidth()];
        for (int y = 0; y < src.getHeight(); y++) {
            for (int x = 0; x < src.getWidth(); x++) {
                if (((src.getRGB(x, y) >> 24) & 0xff) > opaqueLimit) {
                    opaque[y][x] = true;
                }

            }
        }
        return opaque;
    }

    private static boolean isBorder(final int x, final int y,
            final BufferedImage main, final int opaqueLimit) {
        if (isTransparent(x - 1, y - 1, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x, y - 1, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x + 1, y - 1, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x - 1, y, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x + 1, y, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x - 1, y + 1, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x, y + 1, main, opaqueLimit)) {
            return true;
        }
        if (isTransparent(x + 1, y + 1, main, opaqueLimit)) {
            return true;
        }
        return false;

    }

    /**
     * Adds a Glow outside opaque or partial transparent shapes. AntiAliasing is
     * ON
     * 
     * @param src
     *            source image
     * @param glowColor
     *            color of the glow
     * @param radius
     *            radius of the glow
     * @return new BufferedImage, containing glow and source image
     */
    public static BufferedImage addGlow(final BufferedImage src,
            final Color glowColor, final int radius) {
        return addGlow(src, glowColor, radius, 0, true);
    }

    /**
     * 
     * Adds a Glow outside opaque or partial transparent shapes.
     * 
     * @param src
     *            source image
     * @param glowColor
     *            color of the glow
     * @param radius
     *            radius of the glow
     * @param opaqueLimit
     *            sets the opacity limit. range: 0-255
     * @param useAntiAliasing
     *            true, if anti aliasing should be used.
     * @return new BufferedImage, containing glow and source image
     */
    public static BufferedImage addGlow(final BufferedImage src,
            final Color glowColor, final int radius, final int opaqueLimit,
            final boolean useAntiAliasing) {
        BufferedImage ret = getGlow(src, glowColor, radius, opaqueLimit,
                useAntiAliasing);
        Graphics2D g2d = (Graphics2D) ret.getGraphics();
        g2d.drawImage(src, 0, 0, null);
        return ret;
    }

    private static void addGlow(final BufferedImage glow, final int x,
            final int y, final int radius, final int color,
            final boolean[][] opaque) {
        int minX = Math.max(x - radius, 0);
        int maxX = Math.min(glow.getWidth(), x + radius);

        int minY = Math.max(y - radius, 0);
        int maxY = Math.min(glow.getHeight(), y + radius);

        for (int curY = minY; curY < maxY; curY++) {
            for (int curX = minX; curX < maxX; curX++) {
                int curColor = getColor(curX, curY, radius, x, y, color);
                if (!opaque[curY][curX]
                        && ((curColor >> 24) & 0xff) > ((glow.getRGB(curX,
                                curY) >> 24) & 0xff)) {
                    glow.setRGB(curX, curY, curColor);
                }
            }
        }
    }

    private static void setRenderHints(final BufferedImage img) {
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

    }

    private static double getDistance(final int curX, final int curY,
            final int x, final int y, final int radius) {
        return Math.sqrt((curX - x) * (curX - x) + (curY - y) * (curY - y))
                / radius;
    }

    private static boolean isTransparent(final int x, final int y,
            final BufferedImage main, final int opaqueLimit) {
        if (x >= 0 && x < main.getWidth() && y >= 0 && y < main.getHeight()) {
            if (((main.getRGB(x, y) >> 24) & 0xff) <= opaqueLimit) {
                return true;
            }
        }
        return false;
    }

    private static int getColor(final int curX, final int curY,
            final int radius, final int x, final int y, final int color) {
        double distance = getDistance(curX, curY, x, y, radius);
        if (distance > 1)
            return 0;
        int alpha = (color >> 24) & 0xff;

        return ((color & 0x00ffffff) + ((int) (alpha * (1.0 - distance)) << 24));

    }
}

Related Tutorials