130 lines
4.7 KiB
Java
130 lines
4.7 KiB
Java
/**
|
|
* Scale2x.java
|
|
*
|
|
* Written by Markus Persson of Mojang Specifications for a super mario programming contest.
|
|
* Implements the Scale2x algorithm described here: http://scale2x.sourceforge.net/algorithm.html
|
|
* Works on any input image size, and uses a fancy border hack to prevent range checking.
|
|
* It's fast enough for real time use on smaller images (320x240 and thereabouts)
|
|
*
|
|
* This code is public domain. Do whatever you want with it.
|
|
*/
|
|
package dk.itu.mario.engine;
|
|
|
|
import java.awt.Graphics;
|
|
import java.awt.Image;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.DataBufferInt;
|
|
|
|
|
|
public class Scale2x
|
|
{
|
|
private int width;
|
|
private int height;
|
|
|
|
private BufferedImage sourceImage;
|
|
private int[] sourcePixels;
|
|
private Graphics sourceGraphics;
|
|
|
|
private BufferedImage targetImage;
|
|
private int[] targetPixels;
|
|
|
|
/**
|
|
* Creates a new Scale2x object. The new object will scale images of the specified size to images
|
|
* that are twice as large.<br>
|
|
*
|
|
* @param width The width of the images to be scaled
|
|
* @param height The height of the images to be scaled
|
|
*/
|
|
public Scale2x(int width, int height)
|
|
{
|
|
this.width = width;
|
|
this.height = height;
|
|
|
|
// A border of one pixel in each direction, and one down, to avoid if statements in the scale loop
|
|
sourceImage = new BufferedImage(width + 2, height + 3, BufferedImage.TYPE_INT_RGB);
|
|
DataBufferInt sourceDataBuffer = (DataBufferInt) sourceImage.getRaster().getDataBuffer();
|
|
sourcePixels = sourceDataBuffer.getData();
|
|
sourceGraphics = sourceImage.getGraphics();
|
|
|
|
targetImage = new BufferedImage(width * 2, height * 2, BufferedImage.TYPE_INT_RGB);
|
|
DataBufferInt targetDataBuffer = (DataBufferInt) targetImage.getRaster().getDataBuffer();
|
|
targetPixels = targetDataBuffer.getData();
|
|
}
|
|
|
|
/**
|
|
* Scales an image and returns a twice as large image.<br>
|
|
* This assumes the input image is of the dimensions specified in the Scale2x constructor.<br>
|
|
* The returned image is a reference to the internal scale target in this Scale2x, so it
|
|
* will get changed if you call this method again, so don't hold on to it for too long.<br>
|
|
* In other words:<br>
|
|
* <code>Image i0 = scale2x.scale(image0);<br>
|
|
* Image i1 = scale2x.scale(image1);<br>
|
|
* if (i0 == i1) System.exit(0); // Will always terminate</code><br>
|
|
*
|
|
* @param img The image to be scaled
|
|
* @returns A scaled image. If you want that image to survive the next call to this method, make a copy of it.
|
|
*/
|
|
public Image scale(Image img)
|
|
{
|
|
// Offset the image by one pixel so there's a border around it.
|
|
// This lets us avoid having to check that A-I are in range of the image before samping them
|
|
sourceGraphics.drawImage(img, 1, 1, null);
|
|
|
|
int line = width + 2;
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
// Two lines of target pixel pointers
|
|
int tp0 = y * width * 4 - 1;
|
|
int tp1 = tp0 + width * 2;
|
|
|
|
// Three lines of source pixel pointers
|
|
int sp0 = (y) * line;
|
|
int sp1 = (y + 1) * line;
|
|
int sp2 = (y + 2) * line;
|
|
|
|
// Fill the initial A-I values
|
|
int A = sourcePixels[sp0];
|
|
int B = sourcePixels[++sp0];
|
|
int C = sourcePixels[++sp0];
|
|
int D = sourcePixels[sp1];
|
|
int E = sourcePixels[++sp1];
|
|
int F = sourcePixels[++sp1];
|
|
int G = sourcePixels[sp2];
|
|
int H = sourcePixels[++sp2];
|
|
int I = sourcePixels[++sp2];
|
|
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
if (B != H && D != F)
|
|
{
|
|
targetPixels[++tp0] = D == B ? D : E;
|
|
targetPixels[++tp0] = B == F ? F : E;
|
|
targetPixels[++tp1] = D == H ? D : E;
|
|
targetPixels[++tp1] = H == F ? F : E;
|
|
}
|
|
else
|
|
{
|
|
targetPixels[++tp0] = E;
|
|
targetPixels[++tp0] = E;
|
|
targetPixels[++tp1] = E;
|
|
targetPixels[++tp1] = E;
|
|
}
|
|
|
|
// Scroll A-I left
|
|
A = B;
|
|
B = C;
|
|
D = E;
|
|
E = F;
|
|
G = H;
|
|
H = I;
|
|
|
|
// Resample rightmost edge
|
|
C = sourcePixels[++sp0];
|
|
F = sourcePixels[++sp1];
|
|
I = sourcePixels[++sp2];
|
|
}
|
|
}
|
|
|
|
return targetImage;
|
|
}
|
|
} |