Android进阶之路android基础知识学习笔记Android开发经验谈

第12章 图片处理

2018-05-13  本文已影响51人  追梦小乐

本系列学习笔记第12章

前言

打算把android基本知识点写一个系列,旨在把android基础书,例如《Android 第一行代码 第2版》、《爱上android》、《疯狂android讲义》等书的一些知识点记录一下,会持续更新内容,为了方便自己复习,也希望可以帮助到大家!

1、Bitmap和Drawable

1.1 基本介绍

android中常用Bitmap和Drawable显示图片。

Bitmap,称为位图,位图文件格式后缀为bmp,编码器也有很多,例如RGB565、RGB888等,是一种以像素为基本单位作为显示对象,执行率高,但是存储效率低,可以简单理解为存储对象比较好。

Drawable,作为android下通用的图形对象,它可以装载常用格式的图像,比如GIF、PNG、JPG,当然也支持BMP,还提供一些高级的可视化对象,比如渐变、图形等。


image.png

1.2 从资源目录获取BItmap

    public Bitmap getBitmapFromResourse(int resId){
        Resources resources = getResources();
        return BitmapFactory.decodeResource(resources,resId);
    }

1.3 从资源目录获取Drawable


    public Drawable getDrawableFromResourse(int resId){
        Resources resources = getResources();
        Drawable drawable = resources.getDrawable(resId);
        return drawable;
    }

1.4 Bitmap --> Drawable

    public Drawable bitmapToDrawable(Bitmap bitmap){
        Resources resources = getResources();
        BitmapDrawable drawable = new BitmapDrawable(resources, bitmap);
        return drawable;
    }

1.5 Drawable--> Bitmap

    public Bitmap drawableToBitmap(Drawable drawable){
        Resources resources = getResources();
        //创建bitmap
        Bitmap bitmap = Bitmap.createBitmap(
                //drawable本身的宽高
                drawable.getIntrinsicWidth(),
                drawable.getIntrinsicHeight(),
                //根据drawable是否是透明来采取不同的设置
                drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565
        );

        //创建画布
        Canvas canvas = new Canvas(bitmap);
        //设置
        drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
        //把drawable绘制到画布上
        drawable.draw(canvas);

        return bitmap;
    }

1.6 Bitmap的详细讲解

Bitmap压缩方式有:
1)ARGB_8888
2)ARGB_4444(已经放弃)
3)RGB——565
4)ALPHA_8

ARGB的含义:
1)A:Alpha的缩写,代表透明度
2)R:Red的缩写,代表红色
3)G:Green的缩写,代表绿色
4)B:Blue的缩写,代表蓝色

各种压缩方式的区别:
1)Bitmap.Config.ARGB_4444:每个颜色用4位描述,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位,一个字节等于8位,所以每个像素点占了2个byte内存
2)Bitmap.Config.ARGB_8888:每个颜色用4位描述,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位,一个字节等于8位,所以每个像素点占了4个byte内存
3)Bitmap.Config.RGB_565:每个颜色用4位描述,即R=5,G=6,B=5,那么一个像素点占5+6+5=16位,一个字节等于8位,所以每个像素点占了2个byte内存
4)Bitmap.Config.ALPHA_8:只有透明度,没有颜色,透明度占8位,一个字节等于8位,所以每个像素点占了1个byte内存
android默认的颜色模式是ARGB_8888,这个颜色模式色彩最细腻,显示质量最高,但同样,占用的内存也最大。

2、大图的加载

当加载大图片时,加载图片需要的内存空间不是按图片的大小来算的,而是按像素点的多少来算的,图片加载到内存中需要把每一个像素都加载到内存中,对内存的要求非常高。


image.png

2.1 实现图片缩放加载

image.png
image.png
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.photohandledemo.MainActivity">

    <ImageView
        android:id="@+id/iv_photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
 />

</RelativeLayout>
public class MainActivity extends AppCompatActivity {

    private ImageView ivPhoto;
    private String name = "meizi.jpg";
    private Bitmap bitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        loadImage();
    }

    private void loadImage() {
        RxPermissions.getInstance(this).request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean aBoolean) {
                        if (aBoolean){
                            scaleLoadImage();
                        }
                    }
                });
    }

    private void scaleLoadImage(){
        File file = new File(Environment.getExternalStorageDirectory(),name);
        if(!file.exists()){
            return;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();

        //设置为true,代表不加载图片,只是获取图片的宽高
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(file.getAbsolutePath(),options);
        int outWidth = options.outWidth;
        int outHeight = options.outHeight;

        //得到屏幕的宽高
        Display defaultDisplay = getWindowManager().getDefaultDisplay();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        defaultDisplay.getMetrics(displayMetrics);
        int screenWidth = defaultDisplay.getWidth();
        int screenHeight = defaultDisplay.getHeight();

        //计算缩放比例
        int widthScale = screenWidth / outWidth;
        int heightScale = screenHeight / outHeight;
        int scale = widthScale > heightScale ? widthScale :heightScale;

        //设置为false就代表可以加载图片
        options.inJustDecodeBounds = false;
        options.inSampleSize = scale;
        bitmap = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
        ivPhoto.setImageBitmap(bitmap);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (bitmap != null && !bitmap.isRecycled()){
            bitmap.recycle();
        }
    }

    private void initView() {
        ivPhoto = (ImageView) findViewById(R.id.iv_photo);
    }

 
}
image.png

3、图片加水印

图片加水印的原理就是给图片画些东西,主要用到了android提供的俩个类:Canvas 和 Paint。
Canvas 画画板,用于绘制各种图形(点、线、圆、矩形等)


image.png

Paint画笔,和Canvas搭配使用,用于指定绘制的颜色,线条的粗细、过渡、渐变等效果。


image.png image.png
public class DrawMarkActivity extends AppCompatActivity {

    private ImageView ivPhoto;

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

        setContentView(R.layout.activity_draw_mark);

        initView();

        drawMark();
    }

    private void drawMark() {
        //获取原图
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi);

        //获取水印图
        Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        //创建新Bitmap,在这上面合成
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);

        Canvas canvas = new Canvas(newBitmap);
        canvas.drawBitmap(bitmap,0,0,null);

        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
        canvas.drawBitmap(logoBitmap,0,0,paint);
        ivPhoto.setImageBitmap(newBitmap);

    }

    private void initView() {
        ivPhoto = (ImageView) findViewById(R.id.iv_photo);

    }
}
image.png
    private void drawMark() {
        //获取原图
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi);

        //获取水印图
        Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        //创建新Bitmap,在这上面合成
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);

        Canvas canvas = new Canvas(newBitmap);
        canvas.drawBitmap(bitmap,0,0,null);

        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN));
//        canvas.drawBitmap(logoBitmap,0,0,paint);

        paint.setColor(Color.RED);
        paint.setTextSize(50);
        canvas.drawText("追梦小乐",0,100,paint);
        ivPhoto.setImageBitmap(newBitmap);

    }
image.png

4、图片特效:Matrix

图片的特效包括,图形的缩放、倒影、镜面、旋转、位移等。图片的特效是将原图的图形矩阵乘以一个特效矩阵,形成一个新的图形矩阵来实现的。


image.png
image.png

4.1 缩放

image.png
    private void scale(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth() * 2, bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();
        
        //通过矩阵的方式
        float[] value = new float[]{2,0,0,0,1,0,0,0,1};
        matrix.setValues(value);
        
        //不通过矩阵的方式
//        matrix.setScale(2,1,0.5f,0.5f);
        canvas.drawBitmap(bitmap,matrix,null);
        ivPhoto.setImageBitmap(newBitmap);
    }

image.png

4.2 倒影

image.png
    private void reflect(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth() * 2, bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();

        float[] value = new float[]{1,0,0,0,-1,0,0,0,1};
        matrix.setValues(value);

        //超出屏幕了,反方向设置距离让其显示
        matrix.postTranslate(0,bitmap.getHeight());
        canvas.drawBitmap(bitmap,matrix,null);
        ivPhoto.setImageBitmap(newBitmap);
    }
image.png

4.3 镜面

image.png
    private void mirror(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth() * 2, bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();

        float[] value = new float[]{-1,0,0,0,1,0,0,0,1};
        matrix.setValues(value);

        //超出屏幕了,反方向设置距离让其显示
        matrix.postTranslate(bitmap.getWidth(),0);
        canvas.drawBitmap(bitmap,matrix,null);
        ivPhoto.setImageBitmap(newBitmap);
    }
image.png

4.4 旋转

image.png
    private void rotate(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth() * 2, bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();

        matrix.setRotate(30,bitmap.getWidth(),bitmap.getHeight());

        canvas.drawBitmap(bitmap,matrix,null);
        ivPhoto.setImageBitmap(newBitmap);
    }
image.png

4.5 位移

image.png
    private void translate(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi);
        Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth() * 2, bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        Matrix matrix = new Matrix();

        matrix.setTranslate(300,-100);

        canvas.drawBitmap(bitmap,matrix,null);
        ivPhoto.setImageBitmap(newBitmap);
    }

image.png

5、图片颜色处理 ----- 打造自己的美图秀秀

5.1 颜色过滤器ColorMatrixColorFilter

image.png
image.png

5.2 实现图片美化功能

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <ImageView
        android:src="@mipmap/meizi"
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
    <LinearLayout
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="R:"
            />
        <SeekBar
            android:id="@+id/sb_red"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="255" />
    </LinearLayout>
    <LinearLayout
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="G:"
            />
        <SeekBar
            android:id="@+id/sb_green"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="255" />
    </LinearLayout>
    <LinearLayout
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="B:"
            />
        <SeekBar
            android:id="@+id/sb_blue"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="255" />
    </LinearLayout>
    <LinearLayout
        android:padding="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        >
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="RGB:"
            />
        <SeekBar
            android:id="@+id/sb_rgb"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="255" />
    </LinearLayout>
</LinearLayout>
public class MTXXActivity extends AppCompatActivity implements SeekBar.OnSeekBarChangeListener{

    private static final String TAG = MTXXActivity.class.getSimpleName();
    private ImageView iv;
    private SeekBar sbRed;
    private SeekBar sbGreen;
    private SeekBar sbBlue;
    private SeekBar sbRgb;

    private float[] arrays = new float[]{
            1,0,0,0,0,
            0,1,0,0,0,
            0,0,1,0,0,
            0,0,0,1,0
    };

    //声明颜色过滤器
    private ColorFilter colorFilter = new ColorMatrixColorFilter(arrays);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mtxx);

        initView();

        initListener();
    }

    private void initListener() {
        sbRed.setOnSeekBarChangeListener(this);
        sbGreen.setOnSeekBarChangeListener(this);
        sbBlue.setOnSeekBarChangeListener(this);
        sbRgb.setOnSeekBarChangeListener(this);
    }

    private void initView() {
        iv = (ImageView) findViewById(R.id.iv);
        sbRed = (SeekBar) findViewById(R.id.sb_red);
        sbGreen = (SeekBar) findViewById(R.id.sb_green);
        sbBlue = (SeekBar) findViewById(R.id.sb_blue);
        sbRgb = (SeekBar) findViewById(R.id.sb_rgb);
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
        int id = seekBar.getId();
        switch (id){
            case R.id.sb_red:
                arrays[4] = progress;
                break;
            case R.id.sb_green:
                arrays[9] = progress;
                break;
            case R.id.sb_blue:
                arrays[14] = progress;
                break;
            case R.id.sb_rgb:
                arrays[4] = arrays[4] = arrays[4] = progress;
                break;
            default:
                break;
        }
        colorFilter = new ColorMatrixColorFilter(arrays);
        iv.setColorFilter(colorFilter);
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
}

image.png

6、案例 ----- 随手涂鸦

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.baidu.chapter7.section6.HandWritingActivity">
    <ImageView
        android:id="@+id/iv"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:layout_height="0dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:onClick="save"
            android:text="保存"/>
        <Button
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:onClick="clear"
            android:text="清除"/>
    </LinearLayout>

</LinearLayout>

public class HandWritingActivity extends AppCompatActivity implements View.OnTouchListener {

    private ImageView iv;
    private Bitmap bitmap;
    private int startX;
    private int startY;
    private Canvas canvas;
    private Paint paint;

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

        setContentView(R.layout.activity_hand_writing);

        initView();

        initListener();
    }

    private void initListener() {
        iv.setOnTouchListener(this);
    }

    private void initView() {
        iv = (ImageView) findViewById(R.id.iv);
    }

    public void save(View view){
        if (bitmap == null){
            Toast.makeText(this, "没有图片可以保存", Toast.LENGTH_SHORT).show();
            return;
        }
        File file = new File(getCacheDir(),"pic"+System.currentTimeMillis()+".jpg");
        FileOutputStream stream = null;

        try {
            stream = new FileOutputStream(file);

            boolean compress = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
            if (compress){
                Toast.makeText(this, "保存成功"+file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Toast.makeText(this, "保存失败"+e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
        }finally {
            if(stream != null){
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    public void clear(View view){
        if (bitmap != null){
            bitmap = null;
        }
        iv.setImageBitmap(null);
    }

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        switch (motionEvent.getAction()){
            case MotionEvent.ACTION_DOWN:
                if (bitmap == null){
                    bitmap = Bitmap.createBitmap(iv.getWidth(),iv.getHeight(),Bitmap.Config.ARGB_8888);
                    canvas = new Canvas(bitmap);
                    canvas.drawColor(Color.WHITE);
                    paint = new Paint();
                    paint.setColor(Color.RED);
                    paint.setStrokeWidth(5);
                }
                startX = (int) motionEvent.getX();
                startY = (int) motionEvent.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveX = (int) motionEvent.getX();
                int moveY = (int) motionEvent.getY();
                canvas.drawLine(startX,startY,moveX,moveY,paint);
                iv.setImageBitmap(bitmap);
                startX = moveX;
                startY = moveY;
                break;
            default:
                break;
        }
        return true;
    }
}

image.png

7、加载网络图片

7.1 网络图片的缓存策略

爱上Android截图
爱上Android截图
爱上Android截图
爱上Android截图

7.2 图片加载库Picasso的使用

    implementation 'com.squareup.picasso:picasso:2.71828'

优点:
1)使用复杂的图片压缩转换算法来尽可能减少内存消耗
2)自带内存和硬盘缓存二级缓存

基本用法:
1)常用用法

        Picasso.get().load(url).into(iv);

2)对图片进行处理

        Picasso.get()
                .load(url)
                //调整图片大小,节省内存
                .resize(50,50)
                //裁剪模式
                .centerCrop()
                .into(iv);

3)加载占位符及错误图片

        Picasso.get()
                .load(url)
                .placeholder(R.mipmap.ic_launcher)
                .error(R.mipmap.ic_launcher)
                .into(iv);

4)加载res、assert、本地图片资源

        Picasso.get().load(R.drawable.landing_screen).into(imageView1);
        Picasso.get().load("file:///android_asset/DvpvklR.png").into(imageView2);
        Picasso.get().load(new File(...)).into(imageView3);
上一篇下一篇

猜你喜欢

热点阅读