/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.utility.image; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.image.BufferedImage; /** * A bunch of static functions meant to be used as helpers in the various * control paint functions. * * @author David Yazel */ public class DrawingTools { public DrawingTools() { } public static void centerText( Component c, Graphics g, String text ) { ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g.setFont( c.getFont() ); int w = g.getFontMetrics().stringWidth( text ); int h = g.getFontMetrics().getMaxAscent() + g.getFontMetrics().getMaxDescent(); int tx = ( c.getWidth() / 2 ) - ( w / 2 ); int ty = ( c.getHeight() / 2 ) + ( h / 3 ); g.setColor( c.getForeground() ); g.drawString( text, tx, ty ); } public static void centerText( Rectangle r, Graphics g, String text ) { ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); int w = g.getFontMetrics().stringWidth( text ); int h = g.getFontMetrics().getMaxAscent() + g.getFontMetrics().getMaxDescent(); int tx = r.x + ( r.width / 2 ) - ( w / 2 ); int ty = r.y + ( r.height / 2 ) + ( h / 3 ); g.drawString( text, tx, ty ); } public static void drawText( Rectangle r, Graphics g, String text ) { ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); //int w = g.getFontMetrics().stringWidth(text); int h = g.getFontMetrics().getMaxAscent() + g.getFontMetrics().getMaxDescent(); int ty = r.y + ( r.height / 2 ) + ( h / 3 ); g.drawString( text, r.x, ty ); } public static void centerShadowedText( Component c, Graphics g, String text ) { ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); ( (Graphics2D)g ).setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g.setFont( c.getFont() ); int w = g.getFontMetrics().stringWidth( text ); int h = g.getFontMetrics().getMaxAscent() + g.getFontMetrics().getMaxDescent(); int tx = ( c.getWidth() / 2 ) - ( w / 2 ); int ty = ( c.getHeight() / 2 ) + ( h / 4 ); g.setColor( Color.black ); g.drawString( text, tx + 1, ty + 1 ); g.setColor( c.getForeground() ); g.drawString( text, tx, ty ); } public static void drawImageOnCanvas( Graphics g, BufferedImage back, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2 ) { if ( sx2 > back.getWidth() ) { sx2 = back.getWidth(); } if ( sy2 > back.getHeight() ) { sy2 = back.getHeight(); } if ( sx1 >= sx2 ) { return; } if ( sy1 >= sy2 ) { return; } if ( sx1 < 0 ) { return; } if ( sy1 < 0 ) { return; } if ( ( dx2 - dx1 ) != ( sx2 - sx1 ) ) { dx2 = dx1 + ( sx2 - sx1 ); } if ( ( dy2 - dy1 ) != ( sy2 - sy1 ) ) { dy2 = dy1 + ( sy2 - sy1 ); } g.drawImage( back, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null ); } /** * tiles an image horizonatally in 3 segments, the first segment is the left side, the second segment (repeated) * is the middle segment and the final segment is the right hand side. * * @param g * @param image Image containing the segment to be tiled * @param leftWidth The width of the first segment * @param rightWidth The width of the thrid segment * @param dy The destination Y value * @param sy The source Y value * @param width The width of the target area * @param height The height of the target area */ public static void tileSegmentsHorizontally( Graphics g, BufferedImage image, int leftWidth, int rightWidth, int dy, int sy, int width, int height ) { int middleWidth = image.getWidth() - leftWidth - rightWidth; int middleTarget = width - leftWidth - rightWidth; int imageWidth = image.getWidth(); // draw left hand side drawImageOnCanvas( g, image, 0, dy, leftWidth, dy + height, 0, sy, leftWidth, sy + height ); // draw right hand side drawImageOnCanvas( g, image, width - rightWidth, dy, width, dy + height, imageWidth - rightWidth, sy, imageWidth, sy + height ); // now we need to draw as many segments as needed to fill in remainder int amountLeft = middleTarget; int x = leftWidth; int check = 0; while ( amountLeft > 0 ) { // calculate amounts int amount = middleWidth; if ( amount > amountLeft ) { amount = amountLeft; } drawImageOnCanvas( g, image, x, dy, amount, dy + height, leftWidth, sy, leftWidth + amount, sy + height ); // adjust counters x += amount; amountLeft -= amount; if ( ( check++ ) > 10 ) { break; } } } public static void drawSegmentedImage( Graphics g, BufferedImage image, int height, int width, int topWidth, int bottomWidth, int leftWidth, int rightWidth ) { int borderHeight = image.getHeight(); DrawingTools.tileSegmentsHorizontally( g, image, leftWidth, rightWidth, 0, 0, width, topWidth ); DrawingTools.tileSegmentsHorizontally( g, image, leftWidth, rightWidth, height - bottomWidth, borderHeight - bottomWidth, width, bottomWidth ); // now draw any addition bands needed int middleHeight = borderHeight - topWidth - bottomWidth; int middleTarget = height - topWidth - bottomWidth; int amountLeft = middleTarget; int y = topWidth; int check = 0; while ( amountLeft > 0 ) { // calculate amounts int amount = middleHeight; if ( amount > amountLeft ) { amount = amountLeft; } DrawingTools.tileSegmentsHorizontally( g, image, leftWidth, rightWidth, y, topWidth, width, amount ); // adjust counters y += amount; amountLeft -= amount; if ( ( check++ ) > 10 ) { break; } } } public static void drawImageOnCanvas( Graphics g, int x, int y, Rectangle r, BufferedImage back ) { int ux = r.x + (int)r.getWidth(); int uy = r.y + (int)r.getHeight(); int amountX = ( back.getWidth() ); if ( ( amountX + x ) >= ux ) { amountX = ux - x; } int amountY = ( back.getHeight() ); if ( ( amountY + y ) >= uy ) { amountY = uy - y; } g.drawImage( back, x, y, x + amountX, y + amountY, 0, 0, amountX, amountY, null ); } public static void fillWithBackground( Graphics g, Rectangle r, BufferedImage back ) { if ( ( r.x >= back.getWidth() ) || ( r.y >= back.getHeight() ) || ( r.x < 0 ) || ( r.y < 0 ) ) { throw new Error( "Illegal attempt to place an image at " + r.x + "," + r.y + " when image is " + back.getWidth() + "x" + back.getHeight() ); } try { drawImageOnCanvas( g, r.x, r.y, r, back ); } catch ( Exception e ) { throw new Error( "Exception attempting to place an image at " + r.x + "," + r.y + " (" + r.width + "x" + r.height + ") " + " when image is " + back.getWidth() + "x" + back.getHeight() ); } // now loop through and copy the location to the rest of the area assuming that // not all of it is covered. This should be faster than drawing the image // multiple times. int y = r.y; int x = 0; while ( y < ( r.y + r.height ) ) { if ( y == r.y ) { x = r.x + back.getWidth(); } else { x = r.x; } // now loop through the X values while ( x < ( r.x + r.width ) ) { drawImageOnCanvas( g, x, y, r, back ); x += back.getWidth(); } y += back.getHeight(); } } public static void drawBorderedBox( Graphics g, Rectangle r, BufferedImage back, BufferedImage front ) { fillWithBackground( g, r, back ); g.setClip( 4, 4, r.width - 8, r.height - 8 ); fillWithBackground( g, r, front ); g.setClip( 0, 0, r.width, r.height ); Color shadow = new Color( 0f, 0f, 0f, 0.8f ); g.setColor( shadow ); g.drawRect( 0, 0, r.width - 1, r.height - 1 ); } /** * Draws a shadowed rectagle on the supplied graphics context. This is a utility * function to be used in drawing panels and windows. */ public static void drawShadowedBox( Graphics g, Rectangle r, Color highlight, Color shadow, Color internal ) { g.setColor( shadow ); // draw the shadows for the border int tx = r.x + r.width; int ty = r.y + r.height; g.drawLine( r.x + 1, r.y + 1, tx - 3, r.y + 1 ); g.drawLine( r.x, ty - 1, tx - 1, ty - 1 ); g.drawLine( r.x + 1, r.y + 2, r.x + 1, ty - 3 ); g.drawLine( tx - 1, r.y, tx - 1, ty - 1 ); // lower the intensity of the border itself g.setColor( highlight ); g.drawRect( r.x, r.y, r.width - 2, r.height - 2 ); // now drop the intensity of the inside g.setColor( internal ); g.fillRect( r.x + 2, r.y + 2, r.width - 4, r.height - 4 ); } public static void drawBox( Graphics g, Rectangle r, Color highlight, Color shadow ) { g.setColor( shadow ); // draw the shadows for the border int tx = r.x + r.width; int ty = r.y + r.height; g.drawLine( r.x + 1, r.y + 1, tx - 3, r.y + 1 ); g.drawLine( r.x, ty - 1, tx - 1, ty - 1 ); g.drawLine( r.x + 1, r.y + 2, r.x + 1, ty - 3 ); g.drawLine( tx - 1, r.y, tx - 1, ty - 1 ); // lower the intensity of the border itself g.setColor( highlight ); g.drawRect( r.x, r.y, r.width - 2, r.height - 2 ); } public static void drawShadowedBox( Graphics g, Rectangle r, float alpha ) { Color shadow = new Color( 0f, 0f, 0f, 0.8f ); Color highlight = new Color( 0f, 0f, 0f, 0.1f ); Color inside = new Color( 0f, 0f, 0f, alpha ); drawShadowedBox( g, r, highlight, shadow, inside ); } public static void drawShadowedBox( Graphics g, Rectangle r, float highlightAlpha, float shadowAlpha, float insideAlpha ) { Color shadow = new Color( 0f, 0f, 0f, shadowAlpha ); Color highlight = new Color( 1f, 1f, 1f, highlightAlpha ); Color inside = new Color( 0f, 0f, 0f, insideAlpha ); drawShadowedBox( g, r, highlight, shadow, inside ); } public static void adjustAlpha( BufferedImage image, float alpha ) { int n = image.getWidth() * image.getHeight(); int[] pixels = new int[ n ]; image.getRGB( 0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth() ); int a = (int)( 255.0f * alpha ); for ( int i = 0; i < n; i++ ) { pixels[ i ] = ( a << 24 ) | ( pixels[ i ] & 0xffffff ); } image.setRGB( 0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth() ); } }