首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

3.3  绘制图像

Image类用来操作图形图像数据,这些数据可以通过调用低级用户界面的软键绘制在屏幕上,也可以与高级用户界面的某些屏幕类或表单组件关联起来,例如在Alert或者List中使用图形。

3.3.1  生成图像数据

应用程序无法使用new方法生成一个Image类,而是使用Image类的静态函数createImage()方法。Image类提供了7个不同的方法来生成图像数据,依据生成方式的不同,图像可以分为以下两类。

n     不变图像(Immutable-Image):从资源包、文件或者网络上加载图像数据生成,一旦生成,即不能被改变。

n     可变图像(Mutable-Image):可变图像在屏幕外内存中创建,并且可以被修改。

注意

对于在高级用户界面例如Alert、Choice、Form或者ImageItem对象中放置的Image对象,必须是不变图像,因为这些图像被用来在不通知应用程序的情况下更新屏幕内容,只有不变图像才能确保每次更新都是一致的。

以下5个方法可以用来创建常规的不变图像。

n     createImage(String name):从一个命名资源的图像数据中解码生成一个不变图像,这个命名资源常常是一个图片文件。

n     createImage(byte[]imageData,int imageOffset,int imageLength):从存储在字节数组中的数据中生成一个不变图像。

n     createImage(InputStream stream):从数据流中解码生成一个不变图像。

n     createImage(Image source):从源图像中生成一个新的不变图像。

n     createImage(Image image,int x,int y,int width,int height,int transform):从源图像中选取一个区域进行翻转,生成一个新的不变图像。

第一个方法从命名资源中获取图像数据生成一个不变图像,参数name是资源的名称,它所表示的图像数据必须是MIDP实现所支持的图像格式,例如PNG文件格式,有的手机也会支持JPG或者GIF格式,但为了保持较好的移植性,仍建议采用PNG文件。

如果name的值为null,则抛出java.lang.NullPointerException异常。在使用这个方法从命名资源读取数据时,还有可能抛出java.io.IOException异常,而程序中必须对这个异常进行处理,在下列情况下应用程序会抛出I/O异常。

n     所请求的资源不存在。

n     所请求的数据无法加载。

n     所请求的图像数据无法解码。

下面的代码从一个图像文件中读取数据,生成不变图像。

private Image image;

try

{

   image = Image.createImage("/tree.png");       //加载文件资源

}catch(java.io.IOException e)

{

   System.out.println(e.getMessage());           //捕获I/O异常

}

说明

在WTK中,图片文件默认放在工程的res目录下,而且文件名不一定以png为后缀,只要它是能自我识别,且被MIDP实现支持的图像格式文件就可以。

生成图像对象后,可以调用它的isMutable()方法判断图像是否为可变图像,如果是可变的,则返回true,否则返回false。

boolean mutable = image.isMutable();

由于这里笔者创建的是不变图像,因此返回的mutable值都为false。

第二个方法是从一个字节数组中生成一个不变图像对象,它的3个参数共同指定一个数据源,即字节数组imageDate中由偏移量imageOffset和长度imageLength所指定的一个字节数组,然后createImage方法从这个数据源的数据中解码得到新的不变图像对象。

参数imageOffset和imageLength指定了字节数组imageDate的一个范围,imageOffset参数指定相对于第一个数据字节的偏移量,它的范围必须在[0,(imageDate,length-1)]之间,也就是在imageDate数组的长度之内,imageLength参数指定了需要的字节数量,它必须是一个整数,并且保证imageOffset+imageLength不超过imageDate的长度。

public static Image imgPlayer = Image.createImage(

new byte[] { (byte)0x89, (byte)0x50, (byte)0x4E, (byte)0x47, (byte)0x0D, (byte)0x0A, (byte)0x1A, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0D, (byte)0x49, (byte)0x48, (byte)0x44,

…                                        //中间的数据忽略,请参看光盘

(byte)0x00, (byte)0x00, (byte)0x49, (byte)0x45, (byte)0x4E, (byte)0x44, (byte)0xAE, (byte)0x42, (byte)0x60, (byte)0x82

},

(int)0,

(int)162

);

这个方法从一个数组中加载图像数据,比如从记录存储或者从网络上。将上面创建的两个Image图像绘制在屏幕上,如图3-8所示。

第三种方法是MIDP 2.0新增方法,该方法通过从输入流中解码读取图像数据,从而创建新的Image对象,输入流的获取一般是通过getResourceAsStream返回可以获取的数据流,获取对象包括本地文件系统、远程文件系统、JAR包等资源。

图3-8  分别用图片文件和数组创建不变图像

例如笔者将通过输入流的方式读取前面的PNG文件。

try

{

   InputStream stream = getClass().getResourceAsStream("/tree.png");

                                             //用输入流读取文件资源

   if(stream != null)

   {

   image = Image.createImage(stream);        //用读取到的数据创建图片

   }

}catch(java.io.IOException e)

{

   System.out.println(e.getMessage());       //捕获I/O异常

}

第四个方法是从源图像对象中生成一个不变图像,用参数source表示源图像,如果源图像是可变的,那么这个方法将生成一个它的不变图像,内容完全一样。例如在Alert、Choice、ImageItem中只能使用不变图像,用这个方法能够将可变图像应用在这些高级API生成的屏幕中。

第五个方法是MIDP 2.0新增方法,该方法实现了从源图像对象中截取一个区域,并且进行翻转,从而生成一个新的图像对象。

createImage(Image image, int x, int y, int width, int height, int transform);

用参数source表示源图像,(x,y)分别代表所要截取区域的水平坐标和垂直坐标,width和height分别代表所要截取区域的宽度和高度,transform代表复制过程中的翻转方式。MIDP 2.0定义了9种翻转方法,更详细的内容将在Sprite类章节中进行介绍。

n     Sprite.TRANS_NONE:将源图像无翻转地进行复制。

n     Sprite.TRANS_ROT90:将源图像顺时针旋转90°后进行复制。

n     Sprite.TRANS_ROT180:将源图像顺时针旋转180°后进行复制。

n     Sprite.TRANS_ROT270:将源图像顺时针旋转270°后进行复制。

n     Sprite.TRANS_MIRROR:将源图像根据垂直中线镜像翻转后进行复制。

n     Sprite.TRANS_MIRROR_ROT90:将源图像的镜像顺时针旋转90°后进行复制。

n     Sprite.TRANS_MIRROR_ROT180:将源图像的镜像顺时针旋转180°后进行复制。

n     Sprite.TRANS_MIRROR_ROT270:将源图像的镜像顺时针旋转270°后进行复制。

例如下面的代码将前面所创建图像顺时针旋转180°后,生成一幅新的图像。

Image trans_image = Image.createImage(image, 0, 0, image.getWidth()0, image.getHeight()0, Sprite.TRANS_ROT180 );                             //将源图像进行翻转创建新的图像

文本框:  
图3-9  对源图像做翻转处理
将trans_image绘制到屏幕上,如图3-9所示。

3.3.2  图像的锚点

高级用户界面中的不变图像作为不可交互组件,它们的位置由MIDP实现进行控制,通常和其他不可交互的组件放在一行中,按照从左到右的次序排列,并在适当的地方换行。例如,ImageItem中提供了对于图像布局的简单控制,可以插入新行,可以设置左、右对齐和居中对齐。

在低级用户界面中,开发者可以对图像进行像素级的控制。和文本绘制一样,在使用Graphics对象绘制图像时,也提供了锚点的概念,不过图像的锚点和文本的锚点略有不同。

和文本一样,图像也使用限制矩形来确定锚点,不过图像的限制矩形就是它本身所占用的空间,四周不留空隙,因此图像中使用的锚点概念比文本中的简单。

生成一个不变图像后,就可以调用getWidth和getHeight分别返回这个Image对象的宽度和高度,返回值是以像素为单位的整数。例如:

int image_Width = image.getWidth();         //获取图像的宽度

int image_Height = image.getHeight();       //获取图像的高度

文本框:  
图3-10  图像的锚点
如果Image对象是用图像文件生成的,那么返回值image_Width和image_Height就是图3-10中的Width和Height,这样就可以围绕图像确定限制矩形。

为了绘制方便,分别为这个限制矩形制作了垂直中线HCENTER和水平中线VCENTER,把图像的水平方向和垂直方向两等分,这样一共得到3条垂直线:LEFT、HCENTER、RIGHT和3条水平线:TOP、VCENTER、BOTTOM。

这6条线相交得到9个交点,图像的锚点就是这9个点中的一个。锚点用垂直分量和水平分量的OR操作符组合表示。

注意

图像中没有基线这个概念,因此图像的锚点不出现BASELINE,而字体的锚点没有VCENTER。

确定了锚点之后,可以在Canvas中使用Graphics对象的drawImage()方法绘制图像,其定义和drawString()方法的定义类似,如下:

public void drawImage (Image img, int x,int y,int anchor);

参数anchor就是用OR组合起来的锚点常量,参数x和y确定了锚点在坐标系中的位置,参数img就是需要绘制的图像。比如下面的代码,以图像左上方为锚点,并且把锚点定位在Canvas的左上方。

public void paint(Graphics g){ 

  g.setColor(0x00000000);                  //将画笔颜色设置为黑色

  g.fillRect(0, 0, this.getWidth(), this.getHeight());  //用黑色填充屏幕

  g.drawImage(image,0,0,g.TOP|g.LEFT);     //以图片的左上角作为锚点绘制图片

}

图像的绘制效果如图3-11左图所示,如果把绘制语句改为:

g.drawImage(image,getWidth()/2,getHeight()/2,g.VCENTER|g.HCENTER);

则以图片的中心点为锚点,将图片绘制在屏幕的正中央,其绘制效果如图3-11右图所示。

图3-11  用不同的锚点在不同的位置绘制图像

3.3.3  图像的截取

MIDP还提供了一种特别的绘制方法,使用该方法能够截取图像的任何部分绘制到屏幕上,并且该方法允许对源图像进行翻转和镜像处理。该方法的原型为:

void drawRegion(Image src, int x_src, int y_src, int width, int height, int transform, int x_dest, int y_dest, int anchor);

Image对象src为所要绘制的源图像,x_src,y_src分别为图片区域的左上顶点X坐标和Y坐标,width和height分别为截取区域的宽度和高度,transform 定义图片的旋转和镜像方式,取Sprite里的常量,x_dest和y_dest为绘制目标上的坐标值,anchor为图像锚点。

g.setColor(0x00000000);

g.fillRect(0, 0, this.getWidth(), this.getHeight());  //用黑色填充屏幕

try

{

   image = Image.createImage("/tree.png");             //加载图片文件

}catch(java.io.IOException e)

{

   System.out.println(e.getMessage());

}

g.drawRegion(image,10,10,80,80,Sprite.TRANS_ROT270,100,50,g.TOP|g.HCENTER);

                                                      //对图像进行翻转

文本框:  
图3-12  绘制图像部分
区域并且翻转
编译、运行程序,其结果如图3-12所示。

在Graphics对象中绘制图像不受当前颜色、字体的影响,不过和绘制其他几何图形一样,它受当前Rect区域的影响。

3.3.4  图像的透明

在MIDP 2.0中新增了Alpha混合特性,可以使用这个特性来对图片进行一些处理。首先参考一下MIDP 2.0 java doc中关于Alpha Processing的说明:在可变图像中的每个像素都必须是完全模糊的,在不变图像中的每个像素可以是完全透明的、完全模糊的或者介于两者之间的,也就是半透明。

MIDP实现必须支持存储、处理和绘画全透明和全模糊的像素,当从数据源创建一个图片时(数据源可能来自PNG图片、一个字节数组或者输入流),原图片中的不透明像素和透明像素应该在新图片中保持不变。

对半透明像素的处理就和MIDP实现相关了,要看Alpha混合是否被支持。如果系统实现支持Alpha混合,那么原图中的半透明像素在新图片中依然保持半透明,当然数值可能会根据系统支持的半透明的级别发生一些变化。

如果系统实现不支持Alpha混合,任何半透明的像素在新图片中应该使用全透明的像素来替换。MIDP 2.0新增了一个方法用来创建具有Alpha混合特性的Image对象。

public static Image createRGBImage(int[] rgb,int width,int height,boolean processAlpha)

这个方法允许从rgb数组中创建一个不变图像,rgb数组中的数值形式为0xAARRGGBB,其中AA代表透明度,后面的代表颜色值。在数组中的ARGB数据排列方式为水平方向从左到右,垂直方向从上到下。

如果布尔变量processAlpha为1,那么表示高位的Alpha混和值不可忽略,如果Alpha值为0,则对应的像素就为透明,反之如果Alpha值为255,对应的像素为完全不透明。

如果MIDP实现不支持图像的Alpha混和操作,必须使所有的半透明像素变成全透明像素。如果布尔变量processAlpha为0,那么Alpha值将被忽略,所有的像素都将被视为不透明。

说明

alpha属性代表了图片的透明度属性,AA代表透明度,0x00代表全透明,0xFF代表完全模糊。

根据rgb数组内数据的排列方式,像素点在rgb数组中的定位方法为:P(a, b) = rgb[a + b * width],ab分别代表象素在图像中的坐标,并且0 <= a < width和0 <= b < height,width和height分别代表图像的宽和高,以像素为单位。

下面的方法同样是Image类新增的,这个方法可以从图片的指定区域读取ARGB像素值,并存储到rgbData数组中,rgbData中的数据是以0xAARRGGBB格式存储的,代表每个像素的颜色属性和透明属性。

public void getRGB(int[] rgbData, int offset, int scanlength, int x, int y,int width,int height);

返回的rgbData不一定和源图像的实际颜色一致,所有的颜色都可能经过重新采样,以适应当前的显示设备的颜色性能,例如,在黑白手机上,所有的红、绿、蓝像素都将被相应的灰度值所替代。

在不支持Alpha通道的设备上,所有的不透明像素的Alpha值都被设成0xFF(全透明),其他象素的Alpha值都被设成0x00。在支持Alpha通道的设备上,Alpha值同样有可能经过重新采样,以适应当前设备所支持的半透明级数。

scanlength定义了数组的扫描宽度,为了避免数据的交叠,其绝对值必须大于或者等于参数width。(x,y)是图像区域的左上角坐标,width和height分别是所截取图像区域的宽度和高度,以像素为单位。

根据rgb数组内数据的排列方式,像素点在rgb数组中的定位方法为:P(a, b)=rgbData[offset + (a - x) + (b - y) * scanlength],其中x <= a < x + width;y <= b < y + height。

所截取的区域不允许超过源图像,这也意味着对参数还有如下限制:x >= 0;y >= 0;x + width <= image width;y + height <= image height。

文本框:  
图3-13  rgbData数组和源图像的读取关系
如果不满足上述条件,程序将抛出IllegalArgumentException异常,如果width <= 0或者height <= 0,不会抛出异常,但也不会有任何像素数据复制到rgbData数组中。rgbData数组和源图像的读取关系如图3-13所示。

Image类提供了两个方法分别来创建ARGB图像和获取图像数据,相应的Graphics也新增了一个drawRGB方法来绘制RGB图像,详细说明请参看Graphics的颜色模型。

游戏中经常会用到半透明效果。但MIDP 1.0年代只有Nokia和LG两家的扩展API给出了可以处理Alpha通道的API。在MIDP 2.0下,可以用Image类提供的方法得到一个图片的半透明版本。例如下面的代码将生成一个半透明的图像:

try

{

   image = Image.createImage("/tree.png");   //加载图片文件

}catch(java.io.IOException e)

{

   System.out.println(e.getMessage());       //捕获I/O异常

}

int[] argb=new int[image.getWidth()*image.getHeight()];

image.getRGB(argb,0,image.getWidth(),0,0,image.getWidth(),image.getHeight());

                                             //读取图片的ARGB属性

for(int i=0;i<argb.length;i++)

{

   argb[i]&=0xa0ffffff;                      //进行透明处理

}

Image clarity_image = Image.createRGBImage(argb,image.getWidth(),image. getHeight(),true);

g.drawImage(clarity_image,getWidth()/2,getHeight()/2,g.VCENTER|g.HCENTER);

                                             //绘制透明图像

文本框:  
图3-14  对图像做透明处理
编译、运行程序,其结果如图3-14所示。

3.3.5  用Photoshop制作PNG透明背景

可以为PNG文件设置透明区域,这样在设备屏幕中,透过这些区域可以看到图片的背景,图片预览上的灰白方格图案表示透明区域,如图3-15所示。PNG文件支持Alpha透明,Alpha透明常用在包含渐变透明和半透明像素的导出图形中。

下面简要讲解如何用Photoshop和Fireworks制作透明背景,这两种软件还提供别的功能来优化图片文件,具体细节请参看各自的帮助文档。在Photoshop中若要制作PNG透明背景,可以按照如下步骤进行操作。

(1)打开PNG文件,选择【文件】|【存储为Web文件格式】命令。

(2)将文件格式选择为PNG-8,否则无法选择透明色。

注意

尽管在“优化”面板中看不到32位PNG的透明度选项,但32位PNG自动包含透明度。

(3)在颜色面板中选择一种背景颜色,然后将其设置为透明色,如图3-16所示。

     

                 图3-15  图片的背景色不透明和透明                 图3-16  颜色面板

(4)在图片预览中如图3-17所示,单击【存储】按钮,显示【优化结果存储为】对话框,设置保存的文件名,保存格式选为【仅限图像】。

图3-17  优化面板

注意

将颜色设为透明只影响图像的导出版本,而不影响实际图像。可以在预览中查看导出图像的外观。

3.3.6  用Fireworks制作PNG透明背景

在Fireworks MX 2004中若要为图像透明选择一种颜色,可以按照以下步骤进行操作。

文本框:  
图3-18  Fireworks的
优化面板
(1)单击文档窗口左上角的【预览】|【2幅】或【4幅】按钮。在“2幅”或“4幅”视图中,单击除原始视图之外的某个视图。

(2)从优化面板底部的顶部【文件格式】弹出菜单中选择【PNG 8】,在【透明】弹出菜单中选择【索引色透明】,如图3-18所示。

(3)若要选择透明颜色,请单击“选择透明色”按钮。指针变为滴管状。

(4)执行下列操作之一选择要成为透明的颜色。

n     在优化面板颜色表中单击颜色样本。

n     在图片文档中单击一种颜色。

画布颜色在预览中变为透明,如图3-19所示。图形准备好导出。导出时注意保存格式选择【仅图像】。可以观察到,导出的图片大小会比原来的图片大小略有减少。

将透明处理和处理前的图片放置在手机模拟器上比较,如图3-20所示。

        

            图3-19  使用透明功能使图片背景透明               图3-20  在手机上的图片比较

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论