
com.threerings.media.image.NinePatch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nenya Show documentation
Show all versions of nenya Show documentation
Facilities for making networked multiplayer games.
The newest version!
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/nenya
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.media.image;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
/**
* The NinePatch class permits drawing a bitmap in nine sections. The four corners are unscaled;
* the four edges are scaled in one axis, and the middle is scaled in both axes. Normally, the
* middle is transparent so that the patch can provide a selection about a rectangle. Essentially,
* it allows the creation of custom graphics that will scale the way that you define, when content
* added within the image exceeds the normal bounds of the graphic.
*
* This is an AWT clone of the NinePatch functionality that exists in Google's Android graphic
* system. See http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
*/
public class NinePatch
{
/**
* Builds a NinePatch based on the given image.
*
* Figures out the NinePatch bounds by parsing the image: Opaque pixels in the top row
* and left column show the stretchable center. Opaque pixels in the bottom row and right
* column show the content area.
*/
public NinePatch (BufferedImage img)
{
this(img.getSubimage(1, 1, img.getWidth() - 2, img.getHeight() - 2),
getRectangle(img, true), getRectangle(img, false));
}
/**
* Builds a NinePatch based on the given image.
*
* @param center specifies the stretchable center of the image.
* @param content if non-null, specifies the usable content area of the image
*/
public NinePatch (BufferedImage img, Rectangle center, Rectangle content)
{
_img = img;
_left = center.x;
_right = _img.getWidth() - (center.x + center.width);
_top = center.y;
_bottom = _img.getHeight() - (center.y + center.height);
if (content != null) {
_leftPad = content.x;
_rightPad = _img.getWidth() - (content.x + content.width);
_topPad = content.y;
_bottomPad = _img.getHeight() - (content.y + content.height);
} else {
_leftPad = _rightPad = _topPad = _bottomPad = 0;
}
}
public void paint (Graphics2D gfx, Rectangle location)
{
int sx, sy, sw, sh;
int dx, dy, dw, dh;
int width = _img.getWidth();
int height = _img.getHeight();
// Top left
sw = _left;
sh = _top;
sx = 0;
sy = 0;
dw = sw;
dh = sh;
dx = location.x;
dy = location.y;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Top right
sw = _right;
sh = _top;
sx = width - sw;
sy = 0;
dw = sw;
dh = sh;
dx = location.x + location.width - dw;
dy = location.y;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Bottom left
sw = _left;
sh = _bottom;
sx = 0;
sy = height - sh;
dw = sw;
dh = sh;
dx = location.x;
dy = location.y + location.height - dh;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Bottom right
sw = _right;
sh = _bottom;
sx = width - sw;
sy = height - sh;
dw = sw;
dh = sh;
dx = location.x + location.width - dw;
dy = location.y + location.height - dh;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Top center
sw = width - _left - _right;
sh = _top;
sx = _left;
sy = 0;
dw = location.width - _left - _right;
dh = sh;
dx = location.x + _left;
dy = location.y;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Bottom center
sw = width - _left - _right;
sh = _bottom;
sx = _left;
sy = height - _bottom;
dw = location.width - _left - _right;
dh = sh;
dx = location.x + _left;
dy = location.y + location.height - dh;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Left center
sw = _left;
sh = height - _top - _bottom;
sx = 0;
sy = _top;
dw = sw;
dh = location.height - _top - _bottom;
dx = location.x;
dy = location.y + _top;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Right center
sw = _right;
sh = height - _top - _bottom;
sx = width - _right;
sy = _top;
dw = sw;
dh = location.height - _top - _bottom;
dx = location.x + location.width - _right;
dy = location.y + _top;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
// Dead center
sw = width - _left - _right;
sh = height - _top - _bottom;
sx = _left;
sy = _top;
dw = location.width - _left - _right;
dh = location.height - _top - _bottom;
dx = location.x + _left;
dy = location.y + _top;
gfx.drawImage(_img, dx, dy, dx + dw, dy + dh, sx, sy, sx + sw, sy + sh, null);
}
/**
* Returns a rectangle describing the bounds of this NinePatch when drawn such that it frames
* the given content rectangle.
*/
public Rectangle getBoundsSurrounding (Rectangle content)
{
Rectangle bounds = new Rectangle(content);
bounds.width += _leftPad + _rightPad;
bounds.height += _topPad + _bottomPad;
bounds.x -= _leftPad;
bounds.y -= _topPad;
return bounds;
}
/**
* Parses the image to find the bounds of the rectangle defined by pixels on the outside.
*/
protected static Rectangle getRectangle (BufferedImage img, boolean stretch)
{
Rectangle rect = new Rectangle(0, 0, img.getWidth() - 2, img.getHeight() - 2);
for (int xx = 1; xx < rect.width + 1; xx++) {
if (ImageUtil.hitTest(img, xx, stretch ? 0 : img.getHeight() - 1)) {
rect.x = xx - 1;
rect.width -= rect.x;
break;
}
}
for (int xx = img.getWidth() - 1; xx >= rect.x + 1; xx--) {
if (ImageUtil.hitTest(img, xx, stretch ? 0 : img.getHeight() - 1)) {
rect.width = xx - rect.x;
break;
}
}
for (int yy = 1; yy < rect.height + 1; yy++) {
if (ImageUtil.hitTest(img, stretch ? 0 : img.getWidth() - 1, yy)) {
rect.y = yy - 1;
rect.height -= rect.y;
break;
}
}
for (int yy = img.getHeight() - 1; yy >= rect.y + 1; yy--) {
if (ImageUtil.hitTest(img, stretch ? 0 : img.getWidth() - 1, yy)) {
rect.height = yy - rect.y;
break;
}
}
return rect;
}
final protected BufferedImage _img;
/** The size of the non-stretchable regions on each side. */
final protected int _top;
final protected int _bottom;
final protected int _left;
final protected int _right;
/** The amount of padding on each side until we're in the content area. */
final protected int _topPad;
final protected int _bottomPad;
final protected int _leftPad;
final protected int _rightPad;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy