Android Bitmap和Canvas
2010年09月30日
位图是我们开发中最常用的资源,毕竟一个漂亮的界面对用户是最有吸引力的。
1. 从资源中获取位图
可以使用BitmapDrawable或者BitmapFactory来获取资源中的位图。
当然,首先需要获取资源:
Resources res=getResources();
使用BitmapDrawable获取位图
1. 使用BitmapDrawable (InputStream is)构造一个BitmapDrawable;
2. 使用BitmapDrawable类的getBitmap()获取得到位图;
// 读取InputStream并得到位图 Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=InputStream%20is%3Dres.openRa wResource(R.drawable.pic180)%3B%0ABitmapDrawable%20 bmpDraw%3Dnew%20BitmapDrawable(is)%3B%0ABitmap%20bm p%3DbmpDraw.getBitmap()%3B" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
或者采用下面的方式:
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=BitmapDrawable%20bmpDraw%3D(B itmapDrawable)res.getDrawable(R.drawable.pic180)%3B %0ABitmap%20bmp%3DbmpDraw.getBitmap()%3B" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
使用BitmapFactory获取位图
(Creates Bitmap objects from various sources, including files, streams, and byte-arrays.)
使用BitmapFactory类decodeStream(InputStream is)解码位图资源,获取位图。
Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180);
BitmapFactory的所有函数都是static,这个辅助类可以通过资源ID、路径、文件、数据流等方式来获取位图。
以上方法在编程的时候可以自由选择,在Android SDK中说明可以支持的图片格式如下:png (preferred), jpg (acceptable), gif (discouraged),和bmp(Android SDK Support Media Format)。
2. 获取位图的信息
要获取位图信息,比如位图大小、像素、density、透明度、颜色格式等,获取得到Bitmap就迎刃而解了,这些信息在Bitmap的手册中,这里只是辅助说明以下2点:
*
在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题;
*
Bitmap还提供了compress()接口来压缩图片,不过AndroidSAK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了。
3. 显示位图
显示位图可以使用核心类Canvas,通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。当然,也可以通过BitmapDrawable将位图显示到View中。
转换为BitmapDrawable对象显示位图
// 获取位图
Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180);
// 转换为BitmapDrawable对象
BitmapDrawable bmpDraw=new BitmapDrawable(bmp);
// 显示位图
ImageView iv2 = (ImageView)findViewById(R.id.ImageView02);
iv2.setImageDrawable(bmpDraw);
使用Canvas类显示位图
这儿采用一个继承自View的子类Panel,在子类的OnDraw中显示
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=public%20class%20MainActivity %20extends%20Activity%20%7B%0A%20%20%20%20%2F**%20C alled%20when%20the%20activity%20is%20first%20create d.%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20p ublic%20void%20onCreate(Bundle%20savedInstanceState )%20%7B%0A%20%20%20%20%20%20%20%20super.onCreate(sa vedInstanceState)%3B%0A%20%20%20%20%20%20%20%20setC ontentView(new%20Panel(this))%3B%0A%20%20%20%20%7D% 0A%20%20%20%20%0A%20%20%20%20class%20Panel%20extend s%20View%7B%20%20%20%20%20%09%20%20%0A%20%20%20%20% 20%20%20%20public%20Panel(Context%20context)%20%7B% 20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20super(c ontext)%3B%20%0A%20%20%20%20%20%20%20%20%7D%20%20%2 0%20%20%20%0A%20%20%20%20%20%20%20%20public%20void% 20onDraw(Canvas%20canvas)%7B%20%20%0A%20%20%20%20%2 0%20%20%20%20%20%20%20Bitmap%20bmp%20%3D%20BitmapFa ctory.decodeResource(getResources()%2C%20R.drawable .pic180)%3B%20%20%0A%20%20%20%20%20%20%20%20%20%20% 20%20canvas.drawColor(Color.BLACK)%3B%20%20%0A%20%2 0%20%20%20%20%20%20%20%20%20%20canvas.drawBitmap(bm p%2C%2010%2C%2010%2C%20null)%3B%20%20%0A%20%20%20%2 0%20%20%20%20%7D%20%20%0A%20%20%20%20%7D%20%0A%7D" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
public class MainActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new Panel(this)); } class Panel extends View{ public Panel(Context context) { super(context); } public void onDraw(Canvas canvas){ Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); canvas.drawColor(Color.BLACK); canvas.drawBitmap(bmp, 10, 10, null); } } }
4. 位图缩放
(1)将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎一样:drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)。
(2)在原有位图的基础上,缩放原位图,创建一个新的位图:CreateBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)
(3)借助Canvas的scale(float sx, float sy) (Preconcat the current matrix with the specified scale.),不过要注意此时整个画布都缩放了。
(4)借助Matrix:
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=%20%20%20%20%20%20%20%20%20%2 0%20%20Bitmap%20bmp%20%3D%20BitmapFactory.decodeRes ource(getResources()%2C%20R.drawable.pic180)%3B%20% 20%0A%20%20%20%20%20%20%20%20%20%20%20%20Matrix%20m atrix%3Dnew%20Matrix()%3B%0A%20%20%20%20%20%20%20%2 0%20%20%20%20matrix.postScale(0.2f%2C%200.2f)%3B%0A %20%20%20%20%20%20%20%20%20%20%20%20Bitmap%20dstbmp %3DBitmap.createBitmap(bmp%2C0%2C0%2Cbmp.getWidth() %2C%0A%20%20%20%20%20%20%20%20%20%20%20%20bmp.getHe ight()%2Cmatrix%2Ctrue)%3B%0A%20%20%20%20%20%20%20% 20%20%20%20%20canvas.drawColor(Color.BLACK)%3B%20%2 0%0A%20%20%20%20%20%20%20%20%20%20%20%20canvas.draw Bitmap(dstbmp%2C%2010%2C%2010%2C%20null)%3B%20%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
5. 位图旋转
同样,位图的旋转也可以借助Matrix或者Canvas来实现。
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=%20%20%20%20%20%20%20%20%20%2 0%20%20Bitmap%20bmp%20%3D%20BitmapFactory.decodeRes ource(getResources()%2C%20R.drawable.pic180)%3B%20% 20%0A%20%20%20%20%20%20%20%20%20%20%20%20Matrix%20m atrix%3Dnew%20Matrix()%3B%0A%20%20%20%20%20%20%20%2 0%20%20%20%20matrix.postScale(0.8f%2C%200.8f)%3B%0A %20%20%20%20%20%20%20%20%20%20%20%20matrix.postRota te(45)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Bit map%20dstbmp%3DBitmap.createBitmap(bmp%2C0%2C0%2Cbm p.getWidth()%2C%0A%20%20%20%20%20%20%20%20%20%20%20 %20bmp.getHeight()%2Cmatrix%2Ctrue)%3B%0A%20%20%20% 20%20%20%20%20%20%20%20%20canvas.drawColor(Color.BL ACK)%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20ca nvas.drawBitmap(dstbmp%2C%2010%2C%2010%2C%20null)%3 B%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
旋转效果:
6.图片水印的生成方法
生成水印的过程。其实分为三个环节:第一,载入原始图片;第二,载入水印图片;第三,保存新的图片。
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=%20%20%20*%20%2F**%20%0A%20%2 0%20%20*%20%20%20%20%20*%20create%20the%20bitmap%20 from%20a%20byte%20array%20%0A%20%20%20%20*%20%20%20 %20%20*%0A%20%20%20%20*%20%20%20%20%20*%20%40param% 20src%20the%20bitmap%20object%20you%20want%20proecs s%0A%20%20%20%20*%20%20%20%20%20*%20%40param%20wate rmark%20the%20water%20mark%20above%20the%20src%0A%2 0%20%20%20*%20%20%20%20%20*%20%40return%20return%20 a%20bitmap%20object%20%2Cif%20paramter's%20length%2 0is%200%2Creturn%20null%0A%20%20%20%20*%20%20%20%20 %20*%2F%20%0A%20%20%20%20*%20%20%20%20private%20Bit map%20createBitmap(%20Bitmap%20src%2C%20Bitmap%20wa termark%20)%20%20%0A%20%20%20%20*%20%20%20%20%7B%20 %20%0A%20%20%20%20*%20%20%20%20%20%20%20%20String%2 0tag%20%3D%20%22createBitmap%22%3B%20%20%0A%20%20%2 0%20*%20%20%20%20%20%20%20%20Log.d(%20tag%2C%20%22c reate%20a%20new%20bitmap%22%20)%3B%20%20%0A%20%20%2 0%20*%20%20%20%20%20%20%20%20if(%20src%20%3D%3D%20n ull%20)%20%20%0A%20%20%20%20*%20%20%20%20%20%20%20% 20%7B%20%20%0A%20%20%20%20*%20%20%20%20%20%20%20%20 %20%20%20%20return%20null%3B%20%20%0A%20%20%20%20*% 20%20%20%20%20%20%20%20%7D%20%20%0A%20%20%20%20*%20 %20%0A%20%20%20%20*%20%20%20%20%20%20%20%20int%20w% 20%3D%20src.getWidth()%3B%20%20%0A%20%20%20%20*%20% 20%20%20%20%20%20%20int%20h%20%3D%20src.getHeight() %3B%20%20%0A%20%20%20%20*%20%20%20%20%20%20%20%20in t%20ww%20%3D%20watermark.getWidth()%3B%20%20%0A%20% 20%20%20*%20%20%20%20%20%20%20%20int%20wh%20%3D%20w atermark.getHeight()%3B%20%20%0A%20%20%20%20*%20%20 %20%20%20%20%20%20%2F%2Fcreate%20the%20new%20blank% 20bitmap%20%20%0A%20%20%20%20*%20%20%20%20%20%20%20 %20Bitmap%20newb%20%3D%20Bitmap.createBitmap(%20w%2 C%20h%2C%20Config.ARGB_8888%20)%3B%2F%2F%E5%88%9B%E 5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%92%8 CSRC%E9%95%BF%E5%BA%A6%E5%AE%BD%E5%BA%A6%E4%B8%80%E 6%A0%B7%E7%9A%84%E4%BD%8D%E5%9B%BE%20%20%0A%20%20%2 0%20*%20%20%20%20%20%20%20%20Canvas%20cv%20%3D%20ne w%20Canvas(%20newb%20)%3B%20%20%0A%20%20%20%20*%20% 20%20%20%20%20%20%20%2F%2Fdraw%20src%20into%20%20%0 A%20%20%20%20*%20%20%20%20%20%20%20%20cv.drawBitmap (%20src%2C%200%2C%200%2C%20null%20)%3B%2F%2F%E5%9C% A8%200%EF%BC%8C0%E5%9D%90%E6%A0%87%E5%BC%80%E5%A7%8 B%E7%94%BB%E5%85%A5src%20%20%0A%20%20%20%20*%20%20% 20%20%20%20%20%20%2F%2Fdraw%20watermark%20into%20%2 0%0A%20%20%20%20*%20%20%20%20%20%20%20%20cv.drawBit map(%20watermark%2C%20w%20-%20ww%20%2B%205%2C%20h%2 0-%20wh%20%2B%205%2C%20null%20)%3B%2F%2F%E5%9C%A8sr c%E7%9A%84%E5%8F%B3%E4%B8%8B%E8%A7%92%E7%94%BB%E5%8 5%A5%E6%B0%B4%E5%8D%B0%20%20%0A%20%20%20%20*%20%20% 20%20%20%20%20%20%2F%2Fsave%20all%20clip%20%20%0A%2 0%20%20%20*%20%20%20%20%20%20%20%20cv.save(%20Canva s.ALL_SAVE_FLAG%20)%3B%2F%2F%E4%BF%9D%E5%AD%98%20%2 0%0A%20%20%20%20*%20%20%20%20%20%20%20%20%2F%2Fstor e%20%20%0A%20%20%20%20*%20%20%20%20%20%20%20%20cv.r estore()%3B%2F%2F%E5%AD%98%E5%82%A8%20%20%0A%20%20% 20%20*%20%20%20%20%20%20%20%20return%20newb%3B%20%2 0%0A%20%20%20%20*%20%20%20%20%7D%20" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
* /** * * create the bitmap from a byte array * * * * @param src the bitmap object you want proecss * * @param watermark the water mark above the src * * @return return a bitmap object ,if paramter's length is 0,return null * */ * private Bitmap createBitmap( Bitmap src, Bitmap watermark ) * { * String tag = "createBitmap"; * Log.d( tag, "create a new bitmap" ); * if( src == null ) * { * return null; * } * * int w = src.getWidth(); * int h = src.getHeight(); * int ww = watermark.getWidth(); * int wh = watermark.getHeight(); * //create the new blank bitmap * Bitmap newb = Bitmap.createBitmap( w, h, Config.ARGB_8888 );//创建一个新的和SRC长度宽度一样的位图 * Canvas cv = new Canvas( newb ); * //draw src into * cv.drawBitmap( src, 0, 0, null );//在 0,0坐标开始画入src * //draw watermark into * cv.drawBitmap( watermark, w - ww + 5, h - wh + 5, null );//在src的右下角画入水印 * //save all clip * cv.save( Canvas.ALL_SAVE_FLAG );//保存 * //store * cv.restore();//存储 * return newb; * }
7.Canvas的save和restore
onDraw方法会传入一个Canvas对象,它是你用来绘制控件视觉界面的画布。
在onDraw方法里,我们经常会看到调用save和restore方法,它们到底是干什么用的呢?
save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。save和restore之间,往往夹杂的是对Canvas的特殊操作。
例如:我们先想在画布上绘制一个右向的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用)。然后,我们想在右下角有个20像素的圆,那么,onDraw中的核心代码是:
Java代码 type="application/x-shockwave-flash" width="14" height="15" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" src="http://zxl-ong.javaeye.com/javascripts/syntax highlighter/clipboard_new.swf" flashvars="clipboard=int%20px%20%3D%20getMeasuredW idth()%3B%0A%0Aint%20py%20%3D%20getMeasuredWidth()% 3B%0A%0A%2F%2F%20Draw%20background%0A%0Acanvas.draw Rect(0%2C%200%2C%20px%2C%20py%2C%20backgroundPaint) %3B%0A%0Acanvas.save()%3B%0A%0Acanvas.rotate(90%2C% 20px%2F2%2C%20py%2F2)%3B%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%0A%0A%2F%2F%20Draw%20up%20arr ow%0A%0Acanvas.drawLine(px%20%2F%202%2C%200%2C%200% 2C%20py%20%2F%202%2C%20linePaint)%3B%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%0A%0Acanvas.drawL ine(px%20%2F%202%2C%200%2C%20px%2C%20py%20%2F%202%2 C%20linePaint)%3B%0A%0Acanvas.drawLine(px%20%2F%202 %2C%200%2C%20px%20%2F%202%2C%20py%2C%20linePaint)%3 B%0A%0Acanvas.restore()%3B%0A%0A%2F%2F%20Draw%20cir cle%0A%0Acanvas.drawCircle(px%20-%2010%2C%20py%20-% 2010%2C%2010%2C%20linePaint)%3B" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflash player" height="15" width="14">
int px = getMeasuredWidth(); int py = getMeasuredWidth(); // Draw background canvas.drawRect(0, 0, px, py, backgroundPaint); canvas.save(); canvas.rotate(90, px/2, py/2); // Draw up arrow canvas.drawLine(px / 2, 0, 0, py / 2, linePaint); canvas.drawLine(px / 2, 0, px, py / 2, linePaint); canvas.drawLine(px / 2, 0, px / 2, py, linePaint); canvas.restore(); // Draw circle canvas.drawCircle(px - 10, py - 10, 10, linePaint);
效果如图1所示:
如果我们不调用save和restore会是什么样子呢?如图2所示:
从这两个图中,我们就能看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画 布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能造成绘制的图形不同。
本文参考: Android SDK
moandroid.com
http://www.cnblogs.com/xirihanlin/archive/2009/07/ 24/1530246.html