在上一篇博客,Android-图像原理/绘制原理,讲解到绘图原理中,画布 + 画笔🖌️  需要最基本的两个要素,才能绘制出图像;

在上一篇博客,Android-系统绘图真相,讲解到系统内部是如何控制图片的变化,例如:图片缩放/图片旋转/图片平移/等等,以及通过绘图规则 操作图片 旋转 缩放 平移

 

而这篇博客,和以上两篇博客都有关系,也需要理解Android绘图原理 和 Android系统绘图真相;

 

知道了 画布 + 画笔🖌️  这两个要素能够绘制图像后,还需要明白绘图规则:

绘图规则:

      1.在指定的图片上操作,必须要指定好在哪张图片上操作;

      2.必须要给一张空白的图片,然后操作图片;

      3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图

 


 

先画一个线:MyBoardActivity.java

package liudeli.my_media1;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.File;

public class MyBoardActivity extends Activity {

    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_board);

        imageView = findViewById(R.id.image_view);

        /**
         * 加载Sdcard的图片给ImageView显示
         */
        File file = new File(Environment.getExternalStorageDirectory(), "mm.jpg");
        if (file.exists() == false) {
            Toast.makeText(this, file.getName() + "文件不存在", Toast.LENGTH_SHORT).show();
            return;
        }
        // 原始图片
        final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
        imageView.setImageBitmap(bitmap);

        // ---------------------------------

        /**
         * 知道了 画布 + 画笔🖌️  这两个要素能够绘制图像后,还需要明白绘图规则:
         * 绘图规则:
         *
         *       1.在指定的图片上操作,必须要指定好在哪张图片上操作;
         *
         *       2.必须要给一张空白的图片,然后操作图片;
         *
         *       3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图片
         */

        /**
         * 2.必须要给一张空白的图片,然后操作图片;
         *      参数一:空白图片的宽度,就拿原始图片的宽度
         *      参数二:空白图片的高度,就拿原始图片的高度
         *      参数三:空白图片的配置信息,就拿原始图片的配置信息
         */
        final Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());

        // 拿一块新的画布,把空白图片和画布关联
        final Canvas canvas = new Canvas(newBitmap);
        // 设置画布的背景
        canvas.drawColor(Color.WHITE);

        // 拿一只新的画笔
        final Paint paint = new Paint();

        // 给画笔设置红色
        paint.setColor(Color.RED);

        // 设置画笔的粗和细
        paint.setStrokeWidth(5);

        /**
         * 1.在指定的图片上操作,必须要指定好在哪张图片上操作;
         * 参数一:原始的 之前的 bitmap
         * 参数二:注意:⚠ Matrix集结了非常复杂的高等数学运算,操作图片的 图片缩放/图片旋转/图片平移/等等 都是Matrix来计算运算的
         * 参数三:画笔🖌️
         */
        canvas.drawBitmap(bitmap, new Matrix(), paint);

        /*
         * 画线
         * 开始X轴0  结束X轴0  代表是最左上角方开始画
         */
        canvas.drawLine(0, 0, 30, 60, paint);

        /**
         * 3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图片
         */
        imageView.setImageBitmap(newBitmap);
    }

    /**
     * 保存绘制后的图片
     */
    public void drawActio(View view) {

    }
}

 

 


 

设置setOnTouchListener,模仿画板功能:MyBoardActivity.java

  1 package liudeli.my_media1;
  2 
  3 import android.app.Activity;
  4 import android.graphics.Bitmap;
  5 import android.graphics.BitmapFactory;
  6 import android.graphics.Canvas;
  7 import android.graphics.Color;
  8 import android.graphics.Matrix;
  9 import android.graphics.Paint;
 10 import android.os.Bundle;
 11 import android.os.Environment;
 12 import android.util.Log;
 13 import android.view.MotionEvent;
 14 import android.view.View;
 15 import android.widget.ImageView;
 16 import android.widget.Toast;
 17 
 18 import java.io.File;
 19 import java.io.FileNotFoundException;
 20 import java.io.FileOutputStream;
 21 
 22 public class MyBoardActivity extends Activity {
 23 
 24     private final String TAG = MyBoardActivity.class.getSimpleName();
 25 
 26     private ImageView imageView;
 27 
 28     private Canvas canvas;
 29     private Bitmap newBitmap;
 30 
 31     @Override
 32     protected void onCreate(Bundle savedInstanceState) {
 33         super.onCreate(savedInstanceState);
 34 
 35         setContentView(R.layout.activity_board);
 36 
 37         imageView = findViewById(R.id.image_view);
 38 
 39         /**
 40          * 加载Sdcard的图片给ImageView显示
 41          */
 42         File file = new File(Environment.getExternalStorageDirectory(), "mm.jpg");
 43         if (!file.exists() || !file.isFile() ) {
 44             Toast.makeText(this, file.getName() + "文件不存在", Toast.LENGTH_SHORT).show();
 45             return;
 46         }
 47         // 原始图片
 48         final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
 49         imageView.setImageBitmap(bitmap);
 50 
 51         // ---------------------------------
 52 
 53         /**
 54          * 知道了 画布 + 画笔🖌️  这两个要素能够绘制图像后,还需要明白绘图规则:
 55          * 绘图规则:
 56          *
 57          *       1.在指定的图片上操作,必须要指定好在哪张图片上操作;
 58          *
 59          *       2.必须要给一张空白的图片,然后操作图片;
 60          *
 61          *       3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图片
 62          */
 63 
 64         /**
 65          * 2.必须要给一张空白的图片,然后操作图片;
 66          *      参数一:空白图片的宽度,就拿原始图片的宽度
 67          *      参数二:空白图片的高度,就拿原始图片的高度
 68          *      参数三:空白图片的配置信息,就拿原始图片的配置信息
 69          */
 70         newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
 71 
 72         // 拿一块新的画布,把空白图片和画布关联
 73         canvas = new Canvas(newBitmap);
 74         // 设置画布的背景
 75         canvas.drawColor(Color.WHITE);
 76 
 77         // 拿一只新的画笔
 78         final Paint paint = new Paint();
 79 
 80         // 给画笔设置红色
 81         paint.setColor(Color.WHITE);
 82 
 83         // 设置画笔的粗和细
 84         paint.setStrokeWidth(10);
 85 
 86         /**
 87          * 1.在指定的图片上操作,必须要指定好在哪张图片上操作;
 88          * 参数一:原始的 之前的 bitmap
 89          * 参数二:注意:⚠ Matrix集结了非常复杂的高等数学运算,操作图片的 图片缩放/图片旋转/图片平移/等等 都是Matrix来计算运算的
 90          * 参数三:画笔🖌️
 91          */
 92         canvas.drawBitmap(bitmap, new Matrix(), paint);
 93 
 94         /*
 95          * 画线
 96          * 开始X轴0  结束X轴0  代表是最左上角方开始画
 97          */
 98         // 这里注释掉,//canvas.drawLine(0, 0, 60, 90, paint);
 99 
100         /**
101          * 3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图片
102          */
103         imageView.setImageBitmap(newBitmap);
104 
105 
106         /**
107          * ImageView触摸事件监听器,监听到变化就往图片上去涂鸦
108          */
109         imageView.setOnTouchListener(new View.OnTouchListener() {
110 
111             private float startX;
112             private float startY;
113 
114             @Override
115             public boolean onTouch(View v, MotionEvent event) {
116                 MyBoardActivity.super.onTouchEvent(event);
117                 switch (event.getAction()) {
118                     case MotionEvent.ACTION_DOWN: // 当手指按下屏幕
119                         // Log.d(TAG, "按下");
120                         startX = event.getX();
121                         startY = event.getY();
122                         break;
123                     case MotionEvent.ACTION_MOVE: // 手指在触摸着屏幕
124                         // Log.d(TAG, "移动");
125                         float stopX = event.getX();
126                         float stopY = event.getY();
127 
128                         /**
129                          * 画布 提供了可以划线的方法
130                          * 参数一:开始X轴,意思就是:从这里开画
131                          * 参数二:开始Y轴,意思就是:从这里开画
132                          * 参数三:结束X轴,意思就是:画到这里停止
133                          * 参数四:结束Y轴,意思就是:画到这里停止
134                          */
135                         Log.d(TAG, "startX:" + startX + " startY:" + startY + " stopX:" + stopX + " stopY:" + stopY);
136                         canvas.drawLine(startX, startY, stopX, stopY, paint);
137 
138                         /**
139                          * 3.操作图片完成✅后,需要获取结果,操作后的结果就是空白图片
140                          */
141                         imageView.setImageBitmap(newBitmap);
142 
143                         // 把开始位置更新下
144                         startX = stopX;
145                         startY = stopY;
146                         break;
147                     case MotionEvent.ACTION_UP:   // 手指离开了屏幕
148                         Log.d(TAG, "弹起");
149                         break;
150                     default:
151                         break;
152                 }
153 
154                 return true; // 代表我这了处理啦
155             }
156         });
157 
158     }
159 
160     /**
161      * 保存绘制后的图片
162      */
163     public void drawActio(View view) {
164         File file = new File(Environment.getExternalStorageDirectory(), "newSaveImage.jpg");
165         try {
166             FileOutputStream fos = new FileOutputStream(file);
167             /**
168              * Bitmap 提供了 保存图片 的方法
169              * 参数一:保存的图片格式
170              * 参数二:百分比压缩
171              * 参数三:保存需要用到的字节输出流(字节输出流要去绑定file文件路径)
172              * 操作写入Sdcard需要权限
173              */
174             newBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
175         } catch (FileNotFoundException e) {
176             e.printStackTrace();
177             Toast.makeText(this, "保存失败!!!", Toast.LENGTH_SHORT).show();
178         }
179     }
180 }

 

activity_board.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="保存绘制后的图片"
        android:onClick="drawActio"
        />

    <!--
        注意:千万千万千万千万千万千万千万千万千万千万不要这样写,一定要包裹内容才可以
        我就是因为这样写,搞得我调试了一下午来找错误,结果是这里的问题,操你麻痹
        android:layout_width="match_parent"
        android:layout_height="300"
    -->
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

 

在AndroidManifest.xml加入外部写入的权限:

   <!-- Sdcard外部存储的权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

结果:

保存的图片文件: