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

  • 相关阅读:
    uva 11294 Wedding
    uvalive 4452 The Ministers’ Major Mess
    uvalive 3211 Now Or Later
    uvalive 3713 Astronauts
    uvalive 4288 Cat Vs. Dog
    uvalive 3276 The Great Wall Game
    uva 1411 Ants
    uva 11383 Golden Tiger Claw
    uva 11419 SAM I AM
    uvalive 3415 Guardian Of Decency
  • 原文地址:https://www.cnblogs.com/wzc0066/p/2948180.html
Copyright © 2011-2022 走看看