JavaME UI设计之图像特效一

 
通常在做应用时,需要实现图像的部分特效,最简单的方式可以通过美术制作出各种特效的图片,然后用程序来显示即可,但是这样做出来的程序包会很大,而且很浪费内存空间,因此我们需要通过程序来操作图像的每一个像素信息,从而实现各种图片特效,本文就主要针对一些常用的特效进行实现。
在开始具体的特效实现之前,我们需要分析一下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;
}


你可能感兴趣的:(JavaME UI设计之图像特效一)