Java examples for 2D Graphics:BufferedImage Paint
Draws the given BufferedImage to the canvas, at the given coordinates, with the given Effect s applied.
/*//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; } }