我们在玩游戏时经常会看到一些图像的特效,比如半透明等效果。要实现这些效果并不难,只需要对图像本身的像素执行操作。Android中的 Bitmap同样提供了操作像素的方法,可以通过getPixels方法来获得该图像的像素并放到一个数组中,我们处理这个像素数组就可以了,最后通过 setPixels设置这个像素数组到Bitmap中。
在Android中,每一个图像像素通过一个4字节整数来展现:最高位字节用作Alpha通道,即用来实现透明与不透明控制,255代表完全不透明,0则代表完全透明;接下来的一个字节是Red红色通道,255代表完全是红色。依次类推,接下来的两个字节相应地实现绿色和蓝色通道。
下面的示例通过对图像像素的操作来模拟水纹效果,如图5-11所示。
实现代码如下所示:
001 |
package
|
002 |
|
003 |
import
|
004 |
import
|
005 |
import
|
006 |
import
|
007 |
import
|
008 |
import
|
009 |
import
|
010 |
|
011 |
public GameView extends View implements Runnable |
012 |
{ |
013 |
int BACKWIDTH; |
014 |
|
015 |
int BACKHEIGHT; |
016 |
|
017 |
short [] buf2; |
018 |
|
019 |
short [] buf1; |
020 |
|
021 |
int [] Bitmap2; |
022 |
|
023 |
int [] Bitmap1; |
024 |
|
025 |
public GameView(Context context) |
026 |
{
|
027 |
super (context); |
028 |
|
029 |
/** 装载图片 */ |
030 |
Bitmap image = BitmapFactory.decodeResource( this .getResources(),R.drawable.qq); |
031 |
BACKWIDTH = image.getWidth(); |
032 |
BACKHEIGHT = image.getHeight(); |
033 |
|
034 |
buf2 = new short [BACKWIDTH * BACKHEIGHT]; |
035 |
buf1 = new short [BACKWIDTH * BACKHEIGHT]; |
036 |
Bitmap2 = new int [BACKWIDTH * BACKHEIGHT]; |
037 |
Bitmap1 = new int [BACKWIDTH * BACKHEIGHT]; |
038 |
|
039 |
/** 加载图片的像素到数组中 */ |
040 |
image.getPixels(Bitmap1, 0 , BACKWIDTH, 0 , 0 , BACKWIDTH, BACKHEIGHT); |
041 |
|
042 |
new Thread( this ).start(); |
043 |
}
|
044 |
|
045 |
|
046 |
void DropStone( int
// x坐标 |
047 |
int y, // y坐标 |
048 |
int stonesize, // 波源半径
|
049 |
int stoneweight) // 波源能量
|
050 |
{
|
051 |
for ( int
|
052 |
for ( int
|
053 |
if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize) |
054 |
buf1[BACKWIDTH * posy + posx] = ( short ) -stoneweight; |
055 |
}
|
056 |
|
057 |
|
058 |
void RippleSpread() |
059 |
{
|
060 |
for ( int
|
061 |
{ |
062 |
// 波能扩散 |
063 |
buf2[i] = ( short ) (((buf1[i - 1 ] + buf1[i + 1 ] + buf1[i - BACKWIDTH] + buf1[i + BACKWIDTH]) >> 1 ) - buf2[i]);
|
064 |
// 波能衰减 |
065 |
buf2[i] -= buf2[i] >> 5 ; |
066 |
} |
067 |
|
068 |
// 交换波能数据缓冲区 |
069 |
short [] ptmp = buf1; |
070 |
buf1 = buf2; |
071 |
buf2 = ptmp; |
072 |
}
|
073 |
|
074 |
/** 渲染你水纹效果 */ |
075 |
void render() |
076 |
{
|
077 |
int xoff, yoff; |
078 |
int k = BACKWIDTH; |
079 |
for ( int
1 ; i < BACKHEIGHT - 1 ; i++) |
080 |
{ |
081 |
for ( int
0 ; j < BACKWIDTH; j++) |
082 |
{ |
083 |
// 计算偏移量 |
084 |
xoff = buf1[k - 1 ] - buf1[k + 1 ]; |
085 |
yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH]; |
086 |
|
087 |
// 判断坐标是否在窗口范围内 |
088 |
if ((i + yoff) < 0 ) |
089 |
{ |
090 |
k++; |
091 |
continue ; |
092 |
} |
093 |
if ((i + yoff) > BACKHEIGHT) |
094 |
{ |
095 |
k++; |
096 |
continue ; |
097 |
} |
098 |
if ((j + xoff) < 0 ) |
099 |
{ |
100 |
k++; |
101 |
continue ; |
102 |
} |
103 |
if ((j + xoff) > BACKWIDTH) |
104 |
{ |
105 |
k++; |
106 |
continue ; |
107 |
} |
108 |
|
109 |
// 计算出偏移象素和原始象素的内存地址偏移量 |
110 |
int pos1, pos2; |
111 |
pos1 = BACKWIDTH * (i + yoff) + (j + xoff); |
112 |
pos2 = BACKWIDTH * i + j; |
113 |
Bitmap2[pos2++] = Bitmap1[pos1++]; |
114 |
k++; |
115 |
} |
116 |
} |
117 |
}
|
118 |
|
119 |
public void onDraw(Canvas canvas) |
120 |
{
|
121 |
super .onDraw(canvas); |
122 |
|
123 |
/** 绘制经过处理的图片效果 */ |
124 |
canvas.drawBitmap(Bitmap2, 0 , BACKWIDTH, 0 , 0 , BACKWIDTH, BACKHEIGHT, false , null ); |
125 |
}
|
126 |
|
127 |
// 触笔事件 |
128 |
public boolean onTouchEvent(MotionEvent event) |
129 |
{
|
130 |
|
131 |
return true ; |
132 |
}
|
133 |
|
134 |
|
135 |
// 按键按下事件 |
136 |
public boolean onKeyDown( int keyCode, KeyEvent event) |
137 |
{
|
138 |
return true ; |
139 |
}
|
140 |
|
141 |
|
142 |
// 按键弹起事件 |
143 |
public boolean onKeyUp( int keyCode, KeyEvent event) |
144 |
{
|
145 |
DropStone(BACKWIDTH/ 2 , BACKHEIGHT/ 2 , 10 , 30 ); |
146 |
return false ; |
147 |
}
|
148 |
|
149 |
|
150 |
public boolean onKeyMultiple( int keyCode, int
|
151 |
{
|
152 |
return true ; |
153 |
}
|
154 |
|
155 |
/** |
156 |
* 线程处理 |
157 |
*/ |
158 |
public void run() |
159 |
{
|
160 |
while (!Thread.currentThread().isInterrupted()) |
161 |
{ |
162 |
try |
163 |
{ |
164 |
Thread.sleep( 50 ); |
165 |
} |
166 |
catch (InterruptedException e) |
167 |
{ |
168 |
Thread.currentThread().interrupt(); |
169 |
} |
170 |
RippleSpread(); |
171 |
render(); |
172 |
//使用postInvalidate可以直接在线程中更新界面 |
173 |
postInvalidate(); |
174 |
} |
175 |
}
|
176 |
} |
最后,我们就可以用上面的方法实现Android图像像素操作了,谢谢阅读!