A useful class for resizing images (even with alpha transparency!).
Will only work properly with MIDP 2.0
import javax.microedition.lcdui.Image;
public class Resizer {
// fixed point constants
private static final int FP_SHIFT = 13;
private static final int FP_ONE = 1 << FP_SHIFT;
private static final int FP_HALF = 1 << (FP_SHIFT - 1);
// resampling modes - valid values for the mode parameter of resizeImage()
// any other value will default to MODE_BOX_FILTER because of the way the conditionals are set in resizeImage()
public static final int MODE_POINT_SAMPLE = 0;
public static final int MODE_BOX_FILTER = 1;
/**
* getPixels
* Wrapper for pixel grabbing techniques.
* I separated this step into it's own function so that other APIs (Nokia, Motorola, Siemens, etc.) can
* easily substitute the MIDP 2.0 API (Image.getRGB()).
* @param src The source image whose pixels we are grabbing.
* @return An int array containing the pixels in 32 bit ARGB format.
*/
static int[] getPixels(Image src) {
int w = src.getWidth();
int h = src.getHeight();
int[] pixels = new int[w * h];
src.getRGB(pixels,0,w,0,0,w,h);
return pixels;
}
/**
* drawPixels
* Wrapper for pixel drawing function.
* I separated this step into it's own function so that other APIs (Nokia, Motorola, Siemens, etc.) can
* easily substitute the MIDP 2.0 API (Image.createRGBImage()).
* @param pixels int array containing the pixels in 32 bit ARGB format.
* @param w The width of the image to be created.
* @param h The height of the image to be created. This parameter is actually superfluous, because it
* must equal pixels.length / w.
* @return The image created from the pixel array.
*/
static Image drawPixels(int[] pixels, int w, int h) {
return Image.createRGBImage(pixels,w,h,true);
}
static Image resizeImage(Image src, float factor) {
return resizeImage(src, factor, MODE_BOX_FILTER);
}
/**
* resizeImage
* Gets a source image along with new size for it and resizes it.
* @param src The source image.
* @param destW The new width for the destination image.
* @param destH The new heigth for the destination image.
* @param mode A flag indicating what type of resizing we want to do. It currently supports two type:
* MODE_POINT_SAMPLE - point sampled resizing, and MODE_BOX_FILTER - box filtered resizing (default).
* @return The resized image.
*/
static Image resizeImage(Image src, float factor, int mode) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int destW = (int)(srcW * factor);
int destH = (int)(srcH * factor);
// create pixel arrays
int[] destPixels = new int[destW * destH]; // array to hold destination pixels
int[] srcPixels = getPixels(src); // array with source's pixels
if (mode == MODE_POINT_SAMPLE) {
// simple point smapled resizing
// loop through the destination pixels, find the matching pixel on the source and use that
for (int destY = 0; destY < destH; ++destY) {
for (int destX = 0; destX < destW; ++destX) {
int srcX = (destX * srcW) / destW;
int srcY = (destY * srcH) / destH;
destPixels[destX + destY * destW] = srcPixels[srcX + srcY * srcW];
}
}
}
else {
// precalculate src/dest ratios
int ratioW = (srcW << FP_SHIFT) / destW;
int ratioH = (srcH << FP_SHIFT) / destH;
int[] tmpPixels = new int[destW * srcH]; // temporary buffer for the horizontal resampling step
// variables to perform additive blending
int argb; // color extracted from source
int a, r, g, b; // separate channels of the color
int count; // number of pixels sampled for calculating the average
// the resampling will be separated into 2 steps for simplicity
// the first step will keep the same height and just stretch the picture horizontally
// the second step will take the intermediate result and stretch it vertically
// horizontal resampling
for (int y = 0; y < srcH; ++y) {
for (int destX = 0; destX < destW; ++destX) {
count = 0; a = 0; r = 0; b = 0; g = 0; // initialize color blending vars
int srcX = (destX * ratioW) >> FP_SHIFT; // calculate beginning of sample
int srcX2 = ((destX + 1) * ratioW) >> FP_SHIFT; // calculate end of sample
// now loop from srcX to srcX2 and add up the values for each channel
do {
argb = srcPixels[srcX + y * srcW];
a += ((argb & 0xff000000) >> 24); // alpha channel
r += ((argb & 0x00ff0000) >> 16); // red channel
g += ((argb & 0x0000ff00) >> 8); // green channel
b += (argb & 0x000000ff); // blue channel
++count; // count the pixel
++srcX; // move on to the next pixel
}
while (srcX <= srcX2 && srcX + y * srcW < srcPixels.length);
// average out the channel values
a /= count;
r /= count;
g /= count;
b /= count;
// recreate color from the averaged channels and place it into the temporary buffer
tmpPixels[destX + y * destW] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
// vertical resampling of the temporary buffer (which has been horizontally resampled)
for (int x = 0; x < destW; ++x) {
for (int destY = 0; destY < destH; ++destY) {
count = 0; a = 0; r = 0; b = 0; g = 0; // initialize color blending vars
int srcY = (destY * ratioH) >> FP_SHIFT; // calculate beginning of sample
int srcY2 = ((destY + 1) * ratioH) >> FP_SHIFT; // calculate end of sample
// now loop from srcY to srcY2 and add up the values for each channel
do {
argb = tmpPixels[x + srcY * destW];
a += ((argb & 0xff000000) >> 24); // alpha channel
r += ((argb & 0x00ff0000) >> 16); // red channel
g += ((argb & 0x0000ff00) >> 8); // green channel
b += (argb & 0x000000ff); // blue channel
++count; // count the pixel
++srcY; // move on to the next pixel
}
while (srcY <= srcY2 && x + srcY * destW < tmpPixels.length);
// average out the channel values
a /= count; a = (a > 255) ? 255 : a;
r /= count; r = (r > 255) ? 255 : r;
g /= count; g = (g > 255) ? 255 : g;
b /= count; b = (b > 255) ? 255 : b;
// recreate color from the averaged channels and place it into the destination buffer
destPixels[x + destY * destW] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
}
// return a new image created from the destination pixel buffer
return drawPixels(destPixels,destW,destH);
}
}
To copy above code, please open page source and CTRL-C from there.
--thgc