/** * 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.
* * @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.
* This assumes the input image is of the dimensions specified in the Scale2x constructor.
* 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.
* In other words:
* Image i0 = scale2x.scale(image0);
* Image i1 = scale2x.scale(image1);
* if (i0 == i1) System.exit(0); // Will always terminate

* * @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; } }