Draws the given BufferedImage to the canvas, at the given coordinates, with the given Effect s applied. - Java 2D Graphics

Java examples for 2D Graphics:BufferedImage Paint

Description

Draws the given BufferedImage to the canvas, at the given coordinates, with the given Effect s applied.

Demo Code

/*//w  w  w .  ja va  2 s.c o  m
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.awt.image.Raster;
import java.awt.image.RescaleOp;
import java.util.ArrayList;
import java.util.List;

public class Main{
    /**
     * Draws the given {@link BufferedImage} to the canvas, at the given coordinates, with the given
     * {@link Effect}s applied. Note that drawn effects may be outside the bounds of the source
     * image.
     *
     * @param g       The destination canvas.
     * @param source  The source image.
     * @param x       The x offset at which to draw the image.
     * @param y       The y offset at which to draw the image.
     * @param effects The list of effects to apply.
     */
    public static void drawEffects(Graphics2D g, BufferedImage source,
            int x, int y, Effect[] effects) {
        List<ShadowEffect> shadowEffects = new ArrayList<ShadowEffect>();
        List<FillEffect> fillEffects = new ArrayList<FillEffect>();

        for (Effect effect : effects) {
            if (effect instanceof ShadowEffect) {
                shadowEffects.add((ShadowEffect) effect);
            } else if (effect instanceof FillEffect) {
                fillEffects.add((FillEffect) effect);
            }
        }

        Composite oldComposite = g.getComposite();
        for (ShadowEffect effect : shadowEffects) {
            if (effect.inner) {
                continue;
            }

            // Outer shadow
            g.setComposite(AlphaComposite.getInstance(
                    AlphaComposite.SRC_OVER, (float) effect.opacity));
            g.drawImage(
                    filledImage(blurredImage(source, effect.radius),
                            effect.color), (int) effect.xOffset,
                    (int) effect.yOffset, null);
        }
        g.setComposite(oldComposite);

        // Inner shadow & fill effects.
        final Rectangle imageRect = new Rectangle(0, 0, source.getWidth(),
                source.getHeight());
        BufferedImage out = newArgbBufferedImage(imageRect.width,
                imageRect.height);
        Graphics2D g2 = (Graphics2D) out.getGraphics();
        double fillOpacity = 1.0;

        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                1.0f));
        g2.drawImage(source, 0, 0, null);
        g2.setComposite(AlphaComposite.SrcAtop);

        // Gradient fill
        for (FillEffect effect : fillEffects) {
            g2.setPaint(effect.paint);
            g2.fillRect(0, 0, imageRect.width, imageRect.height);
            fillOpacity = Math.max(0, Math.min(1, effect.opacity));
        }

        // Inner shadows
        for (ShadowEffect effect : shadowEffects) {
            if (!effect.inner) {
                continue;
            }

            BufferedImage innerShadowImage = newArgbBufferedImage(
                    imageRect.width, imageRect.height);
            Graphics2D g3 = (Graphics2D) innerShadowImage.getGraphics();
            g3.drawImage(source, (int) effect.xOffset,
                    (int) effect.yOffset, null);
            g2.setComposite(AlphaComposite.getInstance(
                    AlphaComposite.SRC_ATOP, (float) effect.opacity));
            g2.drawImage(
                    filledImage(
                            blurredImage(
                                    invertedAlphaImage(innerShadowImage),
                                    effect.radius), effect.color), 0, 0,
                    null);
        }

        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                (float) fillOpacity));
        g.drawImage(out, x, y, null);
        g.setComposite(oldComposite);
    }
    /**
     * Fills the given {@link BufferedImage} with a {@link Paint}, preserving its alpha channel.
     *
     * @param source The source image.
     * @param paint  The paint to fill with.
     * @return A new, painted/filled image.
     */
    public static BufferedImage filledImage(BufferedImage source,
            Paint paint) {
        BufferedImage newImage = newArgbBufferedImage(source.getWidth(),
                source.getHeight());
        Graphics2D g = (Graphics2D) newImage.getGraphics();
        g.drawImage(source, 0, 0, null);
        g.setComposite(AlphaComposite.SrcAtop);
        g.setPaint(paint);
        g.fillRect(0, 0, source.getWidth(), source.getHeight());
        return newImage;
    }
    /**
     * Applies a gaussian blur of the given radius to the given {@link BufferedImage} using a kernel
     * convolution.
     *
     * @param source The source image.
     * @param radius The blur radius, in pixels.
     * @return A new, blurred image, or the source image if no blur is performed.
     */
    public static BufferedImage blurredImage(BufferedImage source,
            double radius) {
        if (radius == 0) {
            return source;
        }

        final int r = (int) Math.ceil(radius);
        final int rows = r * 2 + 1;
        final float[] kernelData = new float[rows * rows];

        final double sigma = radius / 3;
        final double sigma22 = 2 * sigma * sigma;
        final double sqrtPiSigma22 = Math.sqrt(Math.PI * sigma22);
        final double radius2 = radius * radius;

        double total = 0;
        int index = 0;
        double distance2;

        int x, y;
        for (y = -r; y <= r; y++) {
            for (x = -r; x <= r; x++) {
                distance2 = 1.0 * x * x + 1.0 * y * y;
                if (distance2 > radius2) {
                    kernelData[index] = 0;
                } else {
                    kernelData[index] = (float) (Math.exp(-distance2
                            / sigma22) / sqrtPiSigma22);
                }
                total += kernelData[index];
                ++index;
            }
        }

        for (index = 0; index < kernelData.length; index++) {
            kernelData[index] /= total;
        }

        // We first pad the image so the kernel can operate at the edges.
        BufferedImage paddedSource = paddedImage(source, r);
        BufferedImage blurredPaddedImage = operatedImage(paddedSource,
                new ConvolveOp(new Kernel(rows, rows, kernelData),
                        ConvolveOp.EDGE_ZERO_FILL, null));
        return blurredPaddedImage.getSubimage(r, r, source.getWidth(),
                source.getHeight());
    }
    /**
     * Creates a new ARGB {@link BufferedImage} of the given width and height.
     *
     * @param width  The width of the new image.
     * @param height The height of the new image.
     * @return The newly created image.
     */
    public static BufferedImage newArgbBufferedImage(int width, int height) {
        return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    }
    /**
     * Inverts the alpha channel of the given {@link BufferedImage}. RGB data for the inverted area
     * are undefined, so it's generally best to fill the resulting image with a color.
     *
     * @param source The source image.
     * @return A new image with an alpha channel inverted from the original.
     */
    public static BufferedImage invertedAlphaImage(BufferedImage source) {
        final float[] scaleFactors = new float[] { 1, 1, 1, -1 };
        final float[] offsets = new float[] { 0, 0, 0, 255 };

        return operatedImage(source, new RescaleOp(scaleFactors, offsets,
                null));
    }
    /**
     * Pads the given {@link BufferedImage} on all sides by the given padding amount.
     *
     * @param source  The source image.
     * @param padding The amount to pad on all sides, in pixels.
     * @return A new, padded image, or the source image if no padding is performed.
     */
    public static BufferedImage paddedImage(BufferedImage source,
            int padding) {
        if (padding == 0) {
            return source;
        }

        BufferedImage newImage = newArgbBufferedImage(source.getWidth()
                + padding * 2, source.getHeight() + padding * 2);
        Graphics2D g = (Graphics2D) newImage.getGraphics();
        g.drawImage(source, padding, padding, null);
        return newImage;
    }
    /**
     * Applies a {@link BufferedImageOp} on the given {@link BufferedImage}.
     *
     * @param source The source image.
     * @param op     The operation to perform.
     * @return A new image with the operation performed.
     */
    public static BufferedImage operatedImage(BufferedImage source,
            BufferedImageOp op) {
        BufferedImage newImage = newArgbBufferedImage(source.getWidth(),
                source.getHeight());
        Graphics2D g = (Graphics2D) newImage.getGraphics();
        g.drawImage(source, op, 0, 0);
        return newImage;
    }
}

Related Tutorials