第12章 图片处理

作者: 追梦小乐 | 来源:发表于2018-05-13 21:59 被阅读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);
    

    相关文章

      网友评论

        本文标题:第12章 图片处理

        本文链接:https://www.haomeiwen.com/subject/qsyqdftx.html