zoukankan      html  css  js  c++  java
  • Android系统上绘图功能的实现

    像BufferedImage,Graphics2D以及ImageIO等这些类,在Android SDK中都是没有的,但可以使用android.graphics的一些子类,如canvas,paint等来实现这些绘图功能。按照惯例,先睹demo效果吧:


    下面来描述实现过程。
    库文件主要包括两个类文本:FontProperty和PrintGraphics。其中FontProperty用于定义字体的各个属性,如粗体、斜体、下划线等等;PrintGraphics主要定义各种图形的绘制功能。

    先看FontProperty.java:

    import android.content.Context;
    import android.graphics.Typeface;
     
    public class FontProperty{
    boolean bBold;
    boolean bItalic;
    boolean bUnderLine;
    boolean bStrikeout;
    int iSize;
    Typeface sFace;
     
    /**
    * 设置字体各个属性函数,参数:<br/>
    * boolean bBold - 是否粗体,取值为true/false <br/>
    * boolean bItalic - 是否斜体,取值为true/false <br/>
    * boolean bUnderLine - 是否下划线,取值为true/false <br/>
    * boolean bStrikeout - 是否删除线,取值为true/false <br/>
    * int iSize - 字体大小,取值为一整数 <br/>
    * Typeface sFace - 字体类型,一般设置为null,表示使用系统默认字体 <br/><br/>
    *
    * 示例: <br/>
    * FontProperty fp = new FontProperty(); <br/>
    * fp.setFont(false, true, false, false, 18, null); <br/>
    *
    */

    public void setFont( boolean bBold,
    boolean bItalic,
    boolean bUnderLine,
    boolean bStrikeout,
    int iSize,
    Typeface sFace){
    this.bBold = bBold;
    this.bItalic = bItalic;
    this.bUnderLine = bUnderLine;
    this.bStrikeout = bStrikeout;
    this.iSize = iSize;
    this.sFace = sFace;
    }
     
    /**
    * 通过指定ttf字体库路径初始化sFace字体类型 <br/>
    * 第一个参数:是一个context对象 <br/>
    * 第二个参数:ttf字体库文件的绝对路径 <br/><br/>
    *
    * 示例:<br/>
    * FontProperty fp = new FontProperty(); <br/>
    * fp.setFont(false, false, false, false, 12, null); <br/>
    * fp.initTypeface(getContext(),"/sdcard/a.ttf"); <br/>
    *
    */

    public void initTypeface(Context mContext,String path){
    this.sFace = Typeface.createFromAsset (mContext.getAssets(), path);
    }
     
    /**
    * 通过指定face name初始化sFace字体类型 <br/>
    * 第一个参数如:"DroidSerif-Bold" <br/>
    * 第二个参数取值如下: <br/>
    * Typeface.NORMAL 普通 <br/>
    * Typeface.BOLD 粗体 <br/>
    * Typeface.ITALIC 斜体 <br/>
    * Typeface.BOLD_ITALIC 粗体加斜体 <br/><br/>
    *
    * 示例: <br/>
    * FontProperty fp = new FontProperty(); <br/>
    * fp.setFont(false, false, false, false, 12, null); <br/>
    * fp.initTypefaceToString("DroidSerif-Bold", Typeface.BOLD); <br/>
    */

    public void initTypefaceToString(String familyName, int style){
    this.sFace = Typeface.create(familyName, style);
    }
    }

    除了设置字体属性的方法之外,还提供了两个使用指定字体的函数。

    接着看PrintGraphics.java文件:

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
     
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.graphics.Typeface;
     
    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    import android.graphics.BitmapFactory;
     
    /**
    * PrintGraphics类定义
    */

    public class PrintGraphics{
    //画布
    public Canvas canvas = null;
    //画笔
    public Paint paint = null;
    //位图
    public Bitmap bm = null;
    //画布宽度
    public int width;
    //实际使用的画布长度
    public float length = 0;
     
    /**
    * 获取实际使用的画布长度,并在此基础上增加20px作底边使用
    */

    public int getLength(){
    return (int)this.length+20;
    }
     
    /**
    * 初始化画布,参数为画布的宽度,高度预置为宽度的10倍。<br/><br/>
    * 画布默认定义为白色背景 <br/>
    */

    public void initCanvas(int w){
    int h = 10*w;
    //this.bm = Bitmap.createBitmap(w, h, Config.ARGB_8888);
    //this.bm = Bitmap.createBitmap(w, h, Config.ALPHA_8);
    this.bm = Bitmap.createBitmap(w, h, Config.ARGB_4444);
    this.canvas = new Canvas(this.bm);
    //设置画布颜色为白色
    this.canvas.drawColor(Color.WHITE);
    this.width = w;
    }
     
    /**
    * 初始化画笔,默认画笔的属性为: <br/>
    * 1、消除锯齿 <br/>
    * 2、设置画笔颜色为黑色 <br/>
    * 3、设置图形为空心模式 <br/>
    *
    */

    public void initPaint(){
    this.paint = new Paint();
    //消除锯齿
    this.paint.setAntiAlias(true);
    //设置画笔颜色为黑色
    this.paint.setColor(Color.BLACK);
    //设置图形为空心模式
    this.paint.setStyle(Paint.Style.STROKE);
    }
     
    /**
    * 根据指定的字体属性初始值设置画笔,参数为FontProperty类型
    */

    public void setFontProperty(FontProperty fp) {
    //字体face不为null时,设置使用指定的face;如果给定的face不存在,则使用系统默认
    if(fp.sFace != null){
    try {
    this.paint.setTypeface(fp.sFace);
    } catch (Exception e) {
    this.paint.setTypeface(Typeface.DEFAULT);
    }
    }
    //字体face指定为null时,使用系统默认(推荐将该参数指定为null)
    else{
    this.paint.setTypeface(Typeface.DEFAULT);
    }
     
    //设置是否粗体
    if (fp.bBold) {
    this.paint.setFakeBoldText(true);
    }
    else{
    this.paint.setFakeBoldText(false);
    }
     
    //设置是否斜体
    if (fp.bItalic) {
    this.paint.setTextSkewX(-0.5f);
    }
    else{
    this.paint.setTextSkewX(0);
    }
     
    //设置是否下划线
    if (fp.bUnderLine) {
    this.paint.setUnderlineText(true);
    }
    else{
    this.paint.setUnderlineText(false);
    }
     
    //设置是否删除线(中划线)
    if (fp.bStrikeout) {
    this.paint.setStrikeThruText(true);
    }
    else{
    this.paint.setStrikeThruText(false);
    }
     
    //设置字体大小
    this.paint.setTextSize(fp.iSize);
    }
     
    /**
    * 设置线条宽度
    */

    public void setLineWidth(float w){
    this.paint.setStrokeWidth(w);
    }
     
    /**
    * 绘文本字符串函数,其中(x,y)是指插入文本的左下坐标,所以y不能等于0
    */

    public void drawText(float x, float y, String nStr){
    this.canvas.drawText(nStr, x, y, this.paint);
    //计算实际使用的画布长度,下同
    if(this.length < y){
    this.length = y;
    }
    }
     
    /**
    * 绘直线函数,其中(x1,y1)表示起点坐标,(x2,y2)表示终点坐标
    */

    public void drawLine(float x1, float y1, float x2, float y2){
    this.canvas.drawLine(x1, y1, x2, y2, this.paint);
    float max = 0;
    max = y1>y2?y1:y2;
    if(this.length < max){
    this.length = max;
    }
    }
     
    /**
    * 绘矩形或方形函数,其中(x1,y1)是矩形或方型的左上点坐标,(x2,y2)是矩形或方型的右下点坐标
    */

    public void drawRectangle(float x1, float y1, float x2, float y2){
    this.canvas.drawRect(x1, y1, x2, y2, this.paint);
    float max = 0;
    max = y1>y2?y1:y2;
    if(this.length < max){
    this.length = max;
    }
    }
     
    /**
    * 绘椭圆或正圆函数,其中(x1,y1)是圆外切矩形或方型的左上点坐标,(x2,y2)是圆外切矩形或方型的右下点坐标
    */

    public void drawEllips(float x1, float y1, float x2, float y2){
    RectF re=new RectF(x1, y1, x2, y2);
    this.canvas.drawOval(re, this.paint);
    float max = 0;
    max = y1>y2?y1:y2;
    if(this.length < max){
    this.length = max;
    }
    }
     
    /**
    * 插入指定路径的图片函数,其中(x,y)是指插入图片的左上顶点坐标
    */

    public void drawImage(float x, float y, String path){
    try{
    Bitmap btm = BitmapFactory.decodeFile(path);
    this.canvas.drawBitmap(btm, x, y, null);
    if(this.length < y+btm.getHeight()){
    this.length = y+btm.getHeight();
    }
    }catch (Exception e) {
    e.printStackTrace();
    }
    }
     
    /**
    * 将画布上的图片输出成png图片,路径是/sdcard/0.png
    */

    public void printPng(){
    File f = new File("/sdcard/0.png");
    FileOutputStream fos = null;
    //根据图像实际长度截取画布
    Bitmap nbm = Bitmap.createBitmap(this.bm, 0, 0, this.width, this.getLength());
    try {
    fos = new FileOutputStream(f);
    //第二个参数为压缩率,当格式为PNG时该参数被忽略,其它格式如JPG时会有效,取值范围是0~100,值越大图像越大。
    nbm.compress(Bitmap.CompressFormat.PNG, 50, fos);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    }

    程序里面都有详细的注释信息,所以不难看懂的。

    最后写一个测试demo测试程序了,因为Android部署还涉及到其它文件,所以这里仅给出测试函数,用户可以自己放到一个Activity里面调用测试即可:

    public void myPaint(){
    //获取画图实例
    PrintGraphics pg = new PrintGraphics();
    //初始化画布,宽度为576px,则长度为5760px
    pg.initCanvas(576);
    //初始化画笔
    pg.initPaint();
     
    //插入一张图片,根据自己的图片位置进行更改即可
    pg.drawImage(30, 5, "/sdcard/logo.gif");
     
    //获取字体实例
    FontProperty fp = new FontProperty();
    //初始化字体,黑体,24号
    fp.setFont(true, false, false, false, 24, null);
    pg.setFontProperty(fp);
    //绘制文本
    pg.drawText(215, 45, "北京威控睿博科技有限公司");
     
    //绘制直线
    pg.setLineWidth(5.0f);
    pg.drawLine(0, 70, 576, 70);
     
    //绘制各种格式的文本
    //注意:绘制文本时一定要将线宽恢复到0,特别是开启了下划线和删除线属性
    pg.setLineWidth(0);
    fp.setFont(false, false, false, false, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 95, "这是一行普通文体-Android绘图测试");
     
    fp.setFont(true, false, false, false, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 120, "这是一行粗体文体-Android绘图测试");
     
    fp.setFont(false, true, false, false, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 145, "这是一行斜体文体-Android绘图测试");
     
    fp.setFont(false, false, true, false, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 170, "这是一行下划线文体-Android绘图测试");
     
    fp.setFont(false, false, false, true, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 195, "这是一行删除线文体-Android绘图测试");
     
    fp.setFont(true, true, true, true, 18, null);
    pg.setFontProperty(fp);
    pg.drawText(120, 220, "这是一行混合格式文体-Android绘图测试");
     
    pg.setLineWidth(2.0f);
    pg.drawLine(0, 230, 576, 230);
     
    //绘制矩形
    pg.drawRectangle(10, 250, 370, 430);
     
    //绘制方形
    pg.setLineWidth(4.0f);
    pg.drawRectangle(380, 250, 560, 430);
     
    //绘制椭圆
    pg.setLineWidth(3.0f);
    pg.drawEllips(10, 450, 370, 630);
     
    //绘制正圆
    pg.setLineWidth(6.0f);
    pg.drawEllips(380, 450, 560, 630);
     
    //绘制上述图形的说明文本
    pg.setLineWidth(0);
    fp.setFont(false, false, false, false, 15, null);
    pg.setFontProperty(fp);
    pg.drawText(135, 340, "线宽2.0的矩形");
    pg.drawText(420, 340, "线宽4.0的方形");
    pg.drawText(135, 540, "线宽3.0的椭圆");
    pg.drawText(420, 540, "线宽6.0的正圆");
     
    pg.setLineWidth(4.0f);
    pg.drawLine(0, 650, 576, 650);
     
    //输出图片到/sdcard/0.png
    pg.printPng();
    }

    Demo文件的注释也很详细的,都是调用前面两个库文件定义的功能函数,最后会将图像通过窗口显示出来,同时会保存到/sdcard/0.png。显示效果见文档开始。

    部署程序需要注意的地方:

    0. 开启/sdcard写权限,将下面语句添加到Androidmanifest.xml里面的<manifest>标签中即可:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    1. 绘图中会插入一张图片/sdcard/logo.gif,在手机上当然可以很容易的拷贝到/sdcard目录了,但要通过模拟器测试则同样需要将图片上传到/sdcard:

    $ adb push /path/to/your/logo.gif /sdcard/

    注意:要保证你的模拟器是开启的,且创建模拟器时已经创建了虚拟sdcard,虚拟sdcard的真实位置是:/home/zwang/.android/avd/android2.3.avd/sdcard.img

    2. 因为是调用库函数进行绘图的,所以无法通过view直接展示到屏幕上(或者是我还没找到方法吧,原因如下:如果直接将图绘制到canvas画布上当然是可 以展示出来的,但这样的话就无法对图像进行操控了,所以一般都是先创建一个bitmap缓存,然后被作为参数初始化canvas,这样图像最后都画到 bitmap了,然后就可以对图像进行转换或是保存之类的操作。而通过view展示时,被bitmap初始化的canvas没法作为参数使用,知道解决方 法的请通知我:zwang@ucrobotics.com

    但保存到/sdcard/0.png之后浏览起来也是非常方便的,每次运行完后执行:

    $ adb push /sdcard/0.png /tmp/

    就会将生成到虚拟sdcard里面图像下载到本地的/tmp目录下了。

    3. 每次改动保存之后,Eclipse会自动编译更新apk文件的,所以无需再执行一遍“Run As Android Application”。

    4. Android开发过程中,可以使用logcat进行调试。
    当然了,熟悉eclipse debug使用方法的可能不需要了,对于习惯将信息通过System.out.println()输出进行调试的,就可以通过"$ adb logcat"查看你的输出了。

    5. Eclipse导出jar文件:选中需要导出的java文件(ctrl可多选),右键 Export -> Java -> Jar File,然后Next,输入路径及名称,然后Finish即可(当然jar文件的源文件开始都会包含package xx.xx.xx声明的)。

    6. Eclipse导出说明文档:如果注释写的足够详细和标准,就可以通过eclipse直接超出说明文档,选中project,右键 Export -> Java -> Javadoc,然后Next,输入路径,然后Finish即可。(默认导出的位置是project/doc目录,文档为HTML格式,通过浏览器打开后 如果出现乱码,请选择UTF-8编码浏览)
    可以输出文档的标准注释格式为(可通过添加“<br/>”达到在文档里的分行效果):

    /**
    * comment text <br/><br/>
    * comment more
    */

    整型转换成字节型:

    byte[] b = new byte[2];
    b[0] = (byte)12;
    b[1] = (byte)0x16;

    如果小于128也可以直接赋值,无需使用byte进行强制类型转换的。

    更多绘图示例参见:
    [1] apps.hi.baidu.com/share/detail/18622525
    [2] blog.sina.com.cn/s/blog_61ef49250100qw9x.html
    [3] www.planet-source-code.com/vb/scripts/Sh...Id=4126&lngWId=2

  • 相关阅读:
    pytest框架运用
    unitTest学习
    发送邮件
    python 连接远程服务器,修改时间
    Redis基础
    django 知识点扩展
    ACM 题目 1487: [蓝桥杯][算法提高VIP]不同单词个数统计
    Leetcode 面试题 08.01. 三步问题
    Leetocode 198. 打家劫舍
    Leetcode 121. 买卖股票的最佳时机
  • 原文地址:https://www.cnblogs.com/wzc0066/p/2948180.html
Copyright © 2011-2022 走看看