通常在做应用时,需要实现图像的部分特效,最简单的方式可以通过美术制作出各种特效的图片,然后用程序来显示即可,但是这样做出来的程序包会很大,而且很浪费内存空间,因此我们需要通过程序来操作图像的每一个像素信息,从而实现各种图片特效,本文就主要针对一些常用的特效进行实现。
在开始具体的特效实现之前,我们需要分析一下MIDP2.0中的getRGB(...) 函数,该函数可以将image的alpha以及RGB值转换为一个int数组。 我们可以用该方法以及获得的数组改变图片的alpha,r,g,b值。该函数原型如下:
public void getRGB(int[] rgbData, int offset, int scanlength, int x, int y,int width,int height);
在J2me 里的int是4 bytes的,image中的每个像素以ARGB值的方式描述,每个值可以为0-255。 如果 alpha 值为 0, 对应的像素就为透明,反之如果alpha 值为255, 像素为完全不透明。 其中返回的rgbData不一定和源图像的实际颜色一致,所有的颜色都可能经过重新采样,以适应当前的显示设备的颜色性能,例如,在黑白手机上(现在几乎没有了),所有的红、绿、蓝像素都将被相应的灰度值所替代。在不支持Alpha通道的设备上,所有的不透明像素的Alpha值都被设成0xFF(全透明),其他象素的Alpha值都被设成0x00。在支持Alpha通道的设备上,Alpha值同样有可能经过重新采样,以适应当前设备所支持的半透明级数。另外,scanlength定义了数组的扫描宽度,为了避免数据的交叠,其绝对值必须大于或者等于参数width。(x,y)是图像区域的左上角坐标,width和height分别是所截取图像区域的宽度和高度,以像素为单位。
首先,我们先准备一下两个函数:
/*
*获取图片RGB数据,并返回大小为图片的width*height大小的一维数组
*/
public 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;
}
/*
*将pixels[]里的数据,生成一张图片,图片宽为w,高为h
*/
public Image drawPixels(int[] pixels, int w, int h)
{
Image image = Image.createRGBImage(pixels, w, h, true);
pixels = null;
return image;
}
其中getPixels用于从一个Image中获取像素信息,保存到一个int[]数组中,后面的各种图像特效都将来处理这个int[]数组,而drawPixels函数则用于将一个int[]数组转换一个Image对象,通常用于将一个处理之后的int[]数组合成一个图像用。在开始使用特效之前,我们先看一下准备好的冤死图片如下图所示。
图像缩放
图像缩放算法也很多,这里我们介绍一个比较简单,效果也比较好的算法,其原理就是将图片转换为int[]数组,然后按照缩放的比例从原图片中对应的比例中取得像素信息即可,具体实现代码如下:
/*
* 调整图片大小
destW 调整后的宽,destH调整后的高
*/
public Image effect_resizeImage(Image src,
int destW,
int destH) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] destPixels =
new int[destW * destH];
int[] srcPixels = getPixels(src);
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];
}
}
return drawPixels(destPixels, destW, destH);
}
原图片的宽度和高度为240*99,我们通过该函数将其缩放为120*50之后效果如下图所示。
亮度、对比度
要改变一个图片的亮度和对比度实际上可以通过该百年每个像素的r,g,b颜色值来实现,如果原始值为r,g,b按照对比度c和亮度l改变之后的值为r*c+l,g*c+l,b*c+l即可。最后需要判断每个值是否超过255,如果大于255,则为255。具体实现代码如下:
/*
* 调整图片亮度与对比度。 contrast 对比度,light 亮度
*/
public Image effect_light_contrast(Image src, double contrast, int light) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] srcPixels = getPixels(src);
int r = 0;
int g = 0;
int b = 0;
int a = 0;
int argb;
// 公式y =ax+b a为对比度,b为亮度
// int para_b = light - 127 * (light - 1);
for (int i = 0; i < srcH; i++) {
for (int ii = 0; ii < srcW; ii++) {
argb = srcPixels[i * srcW + ii];
a = ((argb & 0xff000000) >> 24); // alpha channel
r = ((argb & 0x00ff0000) >> 16); // red channel
g = ((argb & 0x0000ff00) >> 8); // green channel
b = (argb & 0x000000ff); // blue channel
r = (int) (r * contrast + light);
g = (int) (g * contrast + light);
b = (int) (b * contrast + light);
if (r > 255)
r = 255;
else if (r < 0)
r = 0;
if (g > 255)
g = 255;
else if (g < 0)
g = 0;
if (b > 255)
b = 255;
else if (b < 0)
b = 0;
srcPixels[i * srcW + ii] = ((a << 24) | (r << 16) | (g << 8) | b);
}
}
return drawPixels(srcPixels, srcW, srcH);
}
使用该函数调整亮度和对比度(effect_light_contrast(mImage,3,20))的效果如下图所示,
图片剪切
图片剪切在MIDP2.0中已经提供了api,这里我们也可以自己实现一个图片剪切的函数,这样在使用时可以更加灵活,具体实现代码如下:
/*
* 图片剪切,cut_xpos,cut_ypos 切割框的起始位置坐标,cut_width,cut_height 切割框的宽与高
*/
public Image effect_cut(Image src, int cut_xpos, int cut_ypos,
int cut_width, int cut_height) {
int srcW = src.getWidth();
int srcH = src.getHeight();
int[] srcPixels = getPixels(src);
int[] desPixels = new int[cut_width * cut_height];
int num = 0;
for (int i = 0; i < srcH; i++) {
if (i >= cut_ypos && i < cut_height + cut_ypos) {
for (int ii = 0; ii < srcW; ii++) {
if (ii >= cut_xpos && ii < cut_width + cut_xpos) {
desPixels[num] = srcPixels[i * srcW + ii];
num++;
}
}
}
}
return drawPixels(desPixels, cut_width, cut_height);
}
使用剪切effect_cut(mImage,50,0,50,50)的效果如下图所示。
添加字符串
给每个图片上添加一个字符串,这个实现过程就很简单了,直接通过getGraphics取得图像的Graphics对象,然后再图片上绘制出字符串即可,具体实现代码如下:
/*
* 图片上添加字符
*/
public Image effect_image_add_str(Image src, String str, int x_pos,
int y_pos) {
Image temp = Image.createImage(src.getWidth(), src.getHeight());
Graphics g = temp.getGraphics();
g.drawImage(src, 0, 0, Graphics.LEFT | Graphics.TOP);
g.setColor(0x000000);
g.drawString(str, x_pos, y_pos, Graphics.LEFT | Graphics.TOP);
return temp;
}
本文分析了如何进行JavaME图形特效的处理,并且分析了几种常见的特效实现,下一篇文章我们将继续分析另外几种特效的原理及实现。
最后附上一个在MIDP1.0中处理图像缩放的函数:
public static Image scaleImage(Image src, int dstW, int dstH) {
int srcW = src.getWidth();
int srcH = src.getHeight();
Image tmp = Image.createImage(dstW, srcH);
Graphics g = tmp.getGraphics();
int delta = (srcW << 16) / dstW;
int pos = delta / 2;
for (int x = 0; x < dstW; x++) {
g.setClip(x, 0, 1, srcH);
g.drawImage(src, x - (pos >> 16), 0, Graphics.LEFT | Graphics.TOP);
pos += delta;
}
Image dst = Image.createImage(dstW, dstH);
g = dst.getGraphics();
delta = (srcH << 16) / dstH;
pos = delta / 2;
for (int y = 0; y < dstH; y++) {
g.setClip(0, y, dstW, 1);
g.drawImage(tmp, 0, y - (pos >> 16), Graphics.LEFT | Graphics.TOP);
pos += delta;
}
return dst;
}