While playing around with Java’s crappy image-stuff, i wrote a simple method to zoom (downscaling is possible, but doesn’t make much sense using this algo) an image using a bilinear filter. It’s halfway optimized (using fixedpoint) and maybe somebody finds it usefull. It doesn’t really fit into anything else i’m doing, so i decided to release it here instead:
import java.awt.*;
import java.awt.image.*;
public class ImageUpscale {
public static Image upscale(Image img, int width, int height) throws Exception {
final int ACC = 512;
final int ACCHX;
final int ACCHY;
final int ACCS = 9;
final int ACCSD = ACCS << 1;
final int ACCMASK = ~511;
int sWidth = img.getWidth(null);
int sHeight = img.getHeight(null);
int length = sWidth * sHeight;
int[] pixels = new int[length];
PixelGrabber pg = new PixelGrabber(img, 0, 0, sWidth, sHeight, pixels, 0, sWidth);
pg.grabPixels();
BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
DataBufferInt data = (DataBufferInt) (dest.getRaster().getDataBuffer());
int[] dPixels = data.getData();
double xf = (double) sWidth / (double) width;
double yf = (double) sHeight / (double) height;
if (xf == (int) xf) {
ACCHX = ACC >> 1;
}
else {
ACCHX = 0;
}
if (yf == (int) yf) {
ACCHY = ACC >> 1;
}
else {
ACCHY = 0;
}
int xfI = (int) (xf * ACC);
int yfI = (int) (yf * ACC);
int sWidthACC = sWidth << ACCS;
int sHeightACC = sHeight << ACCS;
int fsy = 0;
for (int y = 0; y < height; y++) {
int floorY = fsy & ACCMASK;
int ceilY = floorY + ACC;
if (ceilY >= sHeightACC) {
ceilY = floorY;
}
int fracY = (fsy & ~ACCMASK) + ACCHY;
int oppY = ACC - fracY;
int yPos = y * width;
int fyW = (floorY * sWidth) >> ACCS;
int cyW = (ceilY * sWidth) >> ACCS;
int fsx = 0;
int end = width + yPos;
for (int x = yPos; x < end; x++) {
int floorX = fsx & ACCMASK;
int fracX = (fsx & ~ACCMASK) + ACCHX;
int oppX = ACC - fracX;
int ceilX = floorX + ACC;
if (ceilX >= sWidthACC) {
ceilX = floorX;
}
int c1 = pixels[ (floorX >> ACCS) + fyW];
int c2 = pixels[ (ceilX >> ACCS) + fyW];
int c3 = pixels[ (floorX >> ACCS) + cyW];
int c4 = pixels[ (ceilX >> ACCS) + cyW];
int c1r = (c1 >> 16) & 255;
int c1g = (c1 >> 8) & 255;
int c1b = c1 & 255;
int c2r = (c2 >> 16) & 255;
int c2g = (c2 >> 8) & 255;
int c2b = c2 & 255;
int c3r = (c3 >> 16) & 255;
int c3g = (c3 >> 8) & 255;
int c3b = c3 & 255;
int c4r = (c4 >> 16) & 255;
int c4g = (c4 >> 8) & 255;
int c4b = c4 & 255;
int cc1 = oppX * c1r + fracX * c2r;
int cc2 = oppX * c3r + fracX * c4r;
int r = (oppY * cc1 + fracY * cc2) >> ACCSD;
cc1 = oppX * c1g + fracX * c2g;
cc2 = oppX * c3g + fracX * c4g;
int g = (oppY * cc1 + fracY * cc2) >> ACCSD;
cc1 = oppX * c1b + fracX * c2b;
cc2 = oppX * c3b + fracX * c4b;
int b = (oppY * cc1 + fracY * cc2) >> ACCSD;
dPixels[x] = (r << 16) | (g << 8) | b;
fsx += xfI;
}
fsy += yfI;
}
return dest;
}
}