Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2014 Aritz Lopez
   *
   *    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.
  */
 
 package io.github.aritzhack.aritzh.awt.util;
 
 
 import java.awt.*;
 import java.util.*;

Utility class to handle things related to Sprites, such as scaling

Author(s):
Aritz Lopez
 
 public class SpriteUtil {

Creates a new Sprite with a cicle drawn onto it

Parameters:
diameter The diameter of the circle (will be the width and height of the sprite)
color The color of the circle (in ARGB format: 0xAARRGGBB)
lineWidth The thickness of the circle. Warning: if thickness is bigger than 1, it will not draw a perfectly filled circle
Returns:
A new Sprite with a circle drawn onto it
 
 	public static Sprite circle(int diameterint colorint lineWidth) {
 
 		int[] pix = new int[diameter * diameter];
 
 		for (int i = 0; i < lineWidthi++) {
 			drawCircle(pixdiameter - idiametercolor);
 		}
 
 		return new Sprite(diameterdiameterpix);
 	}
 
 	private static void drawCircle(int[] pixint diameterint widthint color) {
 
 		int center = width / 2;
 		int radius = diameter / 2 - 1;
 
 		int d = (5 - (radius * 4)) / 4;
 		int x = 0;
 		int y = radius;
 
 		do {
 			pix[center + x + (center + y) * width] = color;
 			pix[center + x + (center - y) * width] = color;
 			pix[center - x + (center + y) * width] = color;
 			pix[center - x + (center - y) * width] = color;
 			pix[center + y + (center + x) * width] = color;
 			pix[center + y + (center - x) * width] = color;
 			pix[center - y + (center + x) * width] = color;
 			pix[center - y + (center - x) * width] = color;
 
 			if (d < 0) {
 				d += 2 * x + 1;
 			} else {
 				d += 2 * (x - y) + 1;
 				y--;
 			}
 			x++;
 		} while (x <= y);
 	}

Scales an image by a factor, using the given method

Parameters:
original The sprite to scale
scale The factor by which the sprite should be scaled
method The scaling method
Returns:
The scaled sprite
 
 	public static Sprite scale(Sprite originalfloat scaleScalingMethod method) {
 		if (scale == 1.0f) return original.copy();
 
 		switch (method) {
 			case :
 				return scaleNearest(originalscale);
 			case :
 				return scaleBilinear(originalscale);
 		}
		return null;
	}
	private static Sprite scaleNearest(Sprite originalfloat scale) {
		int newWidth = (int) (original.getWidth() * scale);
		int newHeight = (int) (original.getHeight() * scale);
		int[] newPix = new int[newWidth * newHeight];
		int x_ratio = (original.getWidth() << 16) / newWidth + 1;
		int y_ratio = (original.getHeight() << 16) / newHeight + 1;
		for (int i = 0; i < newHeighti++) {
			for (int j = 0; j < newWidthj++) {
				int x2 = (j * x_ratio >> 16);
				int y2 = (i * y_ratio >> 16);
				newPix[(j + i * newWidth)] = original.getPixels()[(x2 + y2 * original.getWidth())];
			}
		}
		return new Sprite(newWidthnewHeightnewPix);
	}
	private static Sprite scaleBilinear(Sprite originalfloat scale) {
		int newWidth = (int) (original.getWidth() * scale);
		int newHeight = (int) (original.getHeight() * scale);
		int[] newPix = new int[newWidth * newHeight];
		int offset = 0;
		float x_ratio = ((float) (original.getWidth() - 1)) / newWidth;
		float y_ratio = ((float) (original.getWidth() - 1)) / newHeight;
		for (int i = 0; i < newHeighti++) {
			for (int j = 0; j < newWidthj++) {
				int x = (int) (x_ratio * j);
				int y = (int) (y_ratio * i);
				float x_diff = (x_ratio * j) - x;
				float y_diff = (y_ratio * i) - y;
				int index = x + y * original.getWidth();
				int a = original.getPixels()[index];
				int b = original.getPixels()[index + 1];
				int c = original.getPixels()[index + original.getWidth()];
				int d = original.getPixels()[index + original.getWidth() + 1];
				newPix[offset++] = bilinearInterpolate(abcdx_diffy_diff);
			}
		}
		return new Sprite(newWidthnewHeightnewPix);
	}
	private static int bilinearInterpolate(int colorAint colorBint colorCint colorDfloat wfloat h) {
		// A*(1-w)*(1-h) + B*w*(1-h) + C*h*(1-w) + D*w*h
		int a = (int) (A.a * (1 - w) * (1 - h) + B.a * w * (1 - h) + C.a * h * (1 - w) + D.a * w * h);
		int r = (int) (A.r * (1 - w) * (1 - h) + B.r * w * (1 - h) + C.r * h * (1 - w) + D.r * w * h);
		int g = (int) (A.g * (1 - w) * (1 - h) + B.g * w * (1 - h) + C.g * h * (1 - w) + D.g * w * h);
		int b = (int) (A.b * (1 - w) * (1 - h) + B.b * w * (1 - h) + C.b * h * (1 - w) + D.b * w * h);
		return ARGBColorUtil.getColor(argb);
	}

Flips a Sprite horizontally (as if it was seen in a mirror above or below it)

Parameters:
original The sprite to flip horizontally
Returns:
The Sprite flipped
	public static Sprite flipH(Sprite original) {
		int[] newPix = new int[original.getPixels().length];
		for (int y = 0; y < original.getHeight(); y++) {
			int newY = original.getHeight() - y - 1;
			for (int x = 0; x < original.getWidth(); x++) {
				newPix[x + newY * original.getWidth()] = original.getPixels()[x + y * original.getWidth()];
			}
		}
		return new Sprite(original.getWidth(), original.getHeight(), newPix);
	}

Flips a Sprite vertically (as if it was seen in a mirror to the left or right)

Parameters:
original The sprite to flip vertically
Returns:
The Sprite flipped
	public static Sprite flipV(Sprite original) {
		int[] newPix = new int[original.getPixels().length];
		for (int x = 0; x < original.getWidth(); x++) {
			int newX = original.getWidth() - x - 1;
			for (int y = 0; y < original.getHeight(); y++) {
				newPix[newX + y * original.getWidth()] = original.getPixels()[x + y * original.getWidth()];
			}
		}
		return new Sprite(original.getWidth(), original.getHeight(), newPix);
	}
	public static BufferedImage toImage(Sprite s) {
		image.setRGB(0, 0, s.getWidth(), s.getHeight(), s.getPixels(), 0, s.getWidth());
		return image;
	}
	public static Set2<SpriteMap<StringRectangle>> packSprites(Map<SpriteStringsprites) {
		int heightSum = 0, widthSum = 0;
		ArrayList<SpritespriteList = new ArrayList<>(sprites.keySet());
		Collections.sort(spriteListnew Comparator<Sprite>() {
			public int compare(Sprite o1Sprite o2) {
				return o1.getWidth() - o2.getWidth();
			}
		});
		for (Sprite s : spriteList) {
			heightSum += s.getHeight();
			widthSum += s.getWidth();
		}
		Map<SpriteRectanglepacking = Maps.newHashMap();
		int x = 0;
		int y = 0;
		int maxY = 0;
		widthSum /= (Math.floor(Math.sqrt(spriteList.size())));
		for (Sprite s : spriteList) {
			if (x + s.getWidth() > widthSum) {
				if(y + s.getHeight() > heightSum) {
					heightSum+=s.getHeight();
				}
				x = 0;
				y += maxY;
				maxY = 0;
			}
			if (s.getHeight() > maxYmaxY = s.getHeight();
			packing.put(snew Rectangle(xys.getWidth(), s.getHeight()));
			x += s.getWidth();
		}
		BufferedImage img = new BufferedImage(widthSumheightSum.);
		for (Map.Entry<SpriteRectanglee : packing.entrySet()) {
			Rectangle rect = e.getValue();
			img.setRGB(rect.xrect.yrect.widthrect.heighte.getKey().getPixels(), 0, rect.width);
		}
		Map<StringRectangleret2 = Maps.newHashMap();
		for (Sprite s : spriteList) {
			String name = sprites.get(s);
			Rectangle rect = packing.get(s);
			ret2.put(namerect);
		}
		return new Set2<>(new Sprite(cropBottomTransparent(img)), ret2);
	}
		int maxY = img.getHeight();
		boolean isTransparent = true;
		while(isTransparent) {
			maxY--;
			if(maxY == 0) break;
			for(int x = 0; x<img.getWidth() && isTransparentx++) {
				if(img.getRGB(xmaxY) != 0) isTransparent = false;
			}
		}
		return img.getSubimage(0, 0, img.getWidth(), maxY+1);
	}
	public static String sheetMapToString(Map<StringRectanglesheet) {
		StringBuilder result = new StringBuilder();
		for (Map.Entry<StringRectanglee : sheet.entrySet()) {
			Rectangle r = e.getValue();
			result
					.append(e.getKey().replaceAll("[^\\w]]""_"))
					.append(".png ")
					.append(r.x)
					.append(" ")
					.append(r.y)
					.append(" ")
					.append(r.width)
					.append(" ")
					.append(r.height)
					.append("\n");
		}
		return result.toString();
	}
	private static int interpolate(int color1int color2int Lfloat l) {
		int a1 = ARGBColorUtil.getAlpha(color1);
		int r1 = ARGBColorUtil.getRed(color1);
		int g1 = ARGBColorUtil.getGreen(color1);
		int b1 = ARGBColorUtil.getBlue(color1);
		int a2 = ARGBColorUtil.getAlpha(color2);
		int r2 = ARGBColorUtil.getRed(color2);
		int g2 = ARGBColorUtil.getGreen(color2);
		int b2 = ARGBColorUtil.getBlue(color2);
		int a3 = (int) (a1 + l * (a2 - a1) / (floatL);
		int r3 = (int) (r1 + l * (r2 - r1) / (floatL);
		int g3 = (int) (g1 + l * (g2 - g1) / (floatL);
		int b3 = (int) (b1 + l * (b2 - b1) / (floatL);
		return ARGBColorUtil.getColor(a3r3g3b3);
	}

Rotates a Sprite

Note: If the angle is either 90, 180, 270 or -90, SpriteUtil.rotate90(Sprite, Rotation) will be used instead, since it is much faster

Parameters:
original The sprite to rotate
angle The rotation angle, in degrees
Returns:
The rotated image
	public static Sprite rotate(Sprite originaldouble angle) {
		if (angle == 90.0) return SpriteUtil.rotate90(original.);
		else if (angle == 180.0) return SpriteUtil.rotate90(original.);
		else if (angle == 270.0 || angle == -90.0) return SpriteUtil.rotate90(original.);
		final double radians = Math.toRadians(angle);
		final double cos = Math.cos(radians);
		final double sin = Math.sin(radians);
		int newWidth = (int) (cos * original.getWidth() + sin * original.getHeight());
		int newHeight = (int) (cos * original.getHeight() + sin * original.getWidth());
		int xDelta = (newWidth - original.getWidth()) / 2;
		int yDelta = (newHeight - original.getHeight()) / 2;
		final int[] pixels2 = new int[newWidth * newHeight];
		int centerX = original.getWidth() / 2;
		int centerY = original.getHeight() / 2;
		for (int x = -xDeltax < newWidth - xDeltax++)
			for (int y = -yDeltay < newHeight - yDeltay++) {
				int m = x - centerX;
				int n = y - centerY;
				int j = (int) (m * cos + n * sin + centerX);
				int k = (int) (n * cos - m * sin + centerY);
				if (j >= 0 && j < original.getWidth() && k >= 0 && k < original.getHeight()) {
					pixels2[(y + yDelta) * newWidth + x + xDelta] = original.getPixels()[k * original.getWidth() + j];
				}
			}
		return new Sprite(newWidthnewHeightpixels2);
	}

Rotates an image by multiples of 90 degrees This is a much faster version of SpriteUtil.rotate(Sprite, double)

Parameters:
original The sprite to rotate
angle The rotation angle
Returns:
The rotated sprite
	public static Sprite rotate90(Sprite originalRotation angle) {
		int newWidth = angle == . ? original.getWidth() : original.getHeight();
		int newHeight = angle == . ? original.getHeight() : original.getWidth();
		int[] newPix = new int[original.getPixels().length];
		for (int x = 0; x < original.getWidth(); x++) {
			for (int y = 0; y < original.getHeight(); y++) {
				int newY = angle == . ? x : angle == . ? original.getHeight() - y - 1 : original.getWidth() - x - 1;
				int newX = angle == . ? original.getHeight() - y - 1 : angle == . ? original.getWidth() - x - 1 : y;
				newPix[newX + newY * newWidth] = original.getPixels()[x + y * original.getWidth()];
			}
		}
		return new Sprite(newWidthnewHeightnewPix);
	}

Adds a border to a Sprite (the border is added inside, so part of the sprite will be covered)

Parameters:
original The sprite to which the border will be added
color The color of the border (in ARGB format: 0xAARRGGBB)
size The sice of the border, in pixels
Returns:
The sprite with the border
	public static Sprite addBorder(Sprite originalint colorint size) {
		int[] newPix = Arrays.copyOf(original.getPixels(), original.getPixels().length);
		for (int x = 0; x < original.getWidth(); x++) {
			for (int y = 0; y < original.getHeight(); y++) {
				if (x < size || x >= original.getWidth() - size || y < size || y >= original.getHeight() - size) {
					newPix[x + y * original.getWidth()] = color;
				}
			}
		}
		return new Sprite(original.getWidth(), original.getHeight(), newPix);
	}

Multiples of 90 for exact rotations
	public enum Rotation {
		_90, _180, _270
	}

Available scaling methods (Wikipedia page)
	public enum ScalingMethod {
Nearest neighbor interpolation (Wikipedia page)
		NEAREST,
Bilinear interpolation (Wikipedia page)
		BILINEAR
	}
New to GrepCode? Check out our FAQ X