手机拍照及简单的图片压缩

Posted 夜尽天明89

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手机拍照及简单的图片压缩相关的知识,希望对你有一定的参考价值。

注释都在代码里,这里就不再说了。特别注意cnClick中的//TODO注释以及onActivityResult方法中的注释
效果图

技术分享

权限:

 <!-- 在SD卡中创建与删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <!-- 向SD卡写入数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

使得屏幕不旋转:

    <activity
       android:name=".MainActivity_21_Photo_Compress_Img"
       android:screenOrientation="portrait"/>

1、布局:
1.1主界面的布局:activity_main_21

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#F6F6F6"
              android:fitsSystemWindows="true"
              android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/search_gold_expert_back_title"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ec434b"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="点击icon"
            android:textColor="#ffffff"
            android:textSize="20sp"/>

    </RelativeLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:overScrollMode="never"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            >

            <ImageView
                android:id="@+id/iv_image"
                android:layout_width="310dp"
                android:layout_height="250dp"
                android:layout_gravity="center_horizontal"
                android:layout_margin="10dp"
                android:src="@mipmap/ic_launcher"/>

            <TextView
                android:id="@+id/show_tv_21"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:background="#ec434b"
                android:gravity="center"
                android:onClick="onClick"
                android:paddingBottom="10dp"
                android:paddingTop="10dp"
                android:text="显示结果"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:text="拍照得到照片的原路径"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/result_url_tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:text="拍照得到照片的大小"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/photo_src_size"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:text="压缩后的图片的路径"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/result_url_tv_2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:text="压缩后照片的大小"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

            <TextView
                android:id="@+id/photo_compress_size"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="10dp"
                android:lineSpacingMultiplier="1.4"
                android:textColor="#4F4F4F"
                android:textSize="16sp"/>

        </LinearLayout>


    </ScrollView>

</LinearLayout>

1.2popupwindow的布局:photo_select_layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:id="@+id/dialog_container"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000000"
        />

    <TextView
        android:id="@+id/pic_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f6f6f6"
        android:gravity="center"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:text="从相册中选取"
        android:textSize="20sp"
        />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000000"
        />

    <TextView
        android:id="@+id/pic_from_take_photo_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f6f6f6"
        android:gravity="center"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:text="拍照"
        android:textSize="20sp"
        />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#000000"
        />

    <TextView
        android:id="@+id/cancle_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#f6f6f6"
        android:gravity="center"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:text="取消"
        android:textSize="20sp"
        />

</LinearLayout>

2、工具类及其他准备的东西
2.1:Utils

 /**
     * 把浮点型数据转换成小数点后2位的数
     * @param f
     * @return
     */
    public static String getNumAccuracy_2(float f) {

        //构造方法的字符格式这里如果小数不足2位,会以0补足.
        DecimalFormat decimalFormat = new DecimalFormat(".00");
        //format 返回的是字符串
        String result = decimalFormat.format(f);
        return result;

    }

2.2:全局变量:CHEN

 /**
     * 图片压缩的边界值。以2M为例。超过2M,就对图片进行压缩
     */
    public static long img_compress_limit = 2 * 1048 * 1024;

    /**
     * 拍照后存储照片的路径
     */
    public static String img_path = Environment.getExternalStorageDirectory() + "/chen/img";

    /**
     * 存放压缩后的图片的路径
     */
    public static String img_compress_path = Environment.getExternalStorageDirectory() + "/chen/compress/";

    public static int picWidth = 1000;
    public static int picHeight = 1000;

2.3:PopSelectListener

/**
 * 图片来源选择的popupwindow
 */
public interface PopSelectListener {

    void popSelect(int flag);
}

2.4:popupwindow:PhotoFromSelectPop

package com.chen.customviewdemo.view;


import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.listener.PopSelectListener;

/**
 * 从底部出来的PopupWindow
 */
public class PhotoFromSelectPop {

    Context context;
    private PopupWindow popupWindow;
    View popupWindowView;

    public PhotoFromSelectPop(Context context) {
        this.context = context;
    }

    /**
     * 初始化
     */
    public void initPopupWindow(final PopSelectListener listener) {

        popupWindowView = LayoutInflater.from(context).inflate(R.layout.photo_select_layout, null);
        popupWindow = new PopupWindow(popupWindowView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

        popupWindow.setAnimationStyle(R.style.BottompSelectAnimationShow);
        // 菜单背景色。加了一点透明度
        ColorDrawable dw = new ColorDrawable(0xddffffff);
        popupWindow.setBackgroundDrawable(dw);

        popupWindow.showAtLocation(LayoutInflater.from(context).inflate(R.layout.activity_main, null),
                Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);

        // 设置背景半透明
        backgroundAlpha(0.7f);

        popupWindow.setOnDismissListener(new popupDismissListener());

        popupWindowView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });

        popupWindowView.findViewById(R.id.pic_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                listener.popSelect(0);
                dimss();
            }
        });

        popupWindowView.findViewById(R.id.pic_from_take_photo_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                listener.popSelect(1);
                dimss();
            }
        });

        popupWindowView.findViewById(R.id.cancle_tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dimss();
            }
        });

    }

    /**
     * 设置添加屏幕的背景透明度
     *
     * @param bgAlpha
     */
    public void backgroundAlpha(float bgAlpha) {
        WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
        lp.alpha = bgAlpha; // 0.0-1.0
        ((Activity) context).getWindow().setAttributes(lp);
    }

    class popupDismissListener implements PopupWindow.OnDismissListener {

        @Override
        public void onDismiss() {
            backgroundAlpha(1f);
        }
    }

    public void dimss() {
        if (popupWindow != null) {
            popupWindow.dismiss();
        }
    }


}

2.4.1:styles.xml

   <style name="BottompSelectAnimationShow">
        <item name="android:windowEnterAnimation">@anim/bottom_enter</item>
        <item name="android:windowExitAnimation">@anim/bottom_exit</item>
    </style>

2.4.2:bottom_enter

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="500"/>

</set>

2.4.3:bottom_exit

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

    <translate
        android:duration="500"
        android:fromYDelta="0"
        android:toYDelta="100%"/>

</set>

2.5:FileHelper


import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;


public class FileHelper {

    /**
     * 检查指定路径下的文件尺寸
     *
     * @param filePath
     * @return
     */
    public static String checkFileSize(String filePath) {
        File file = new File(filePath);
        if (file.length() > CHEN.img_compress_limit) {
            System.out.print("照片大于2M进行压缩=" + file.length());
            String compress_img = CHEN.img_compress_path + System.currentTimeMillis() + ".jpg";
            compressPic(filePath, compress_img);
            return compress_img;
        } else {
            return filePath;
        }
    }

    /**
     * 压缩图片
     *
     * @param fromPicUrl
     */
    public static void compressPic(String fromPicUrl, String compress_img_path) {

        int width = CHEN.picWidth;
        int height = CHEN.picHeight;

        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true; // 翻译:只是解码边界
        // 当opts不为null时,但decodeFile返回空,
        // 不为图片分配内存,只获取图片的大小,并保存在opts的outWidth和outHeight
        Bitmap bitmap = BitmapFactory.decodeFile(fromPicUrl, opts);

        int srcWidth = opts.outWidth; // 获得原始图片的长
        int srcHeight = opts.outHeight; // 获得原始图片的宽
        Log.e("CHEN", "原始图片的宽高=" + srcWidth + "/" + srcHeight);

        opts.inJustDecodeBounds = false; // 设置加载照片进入内存中
        int be = 0; // 缩放倍数(如果为2,则长,宽各自缩短一倍,整张图片缩短至四分之一)
        int x = 0; // 长的倍数
        int y = 0; // 宽的倍数

        if (srcWidth > srcHeight) {
            x = srcWidth / width;
            y = srcHeight / height;
        } else {
            x = srcWidth / height;
            y = srcHeight / width;
        }

        if (x > y) {
            be = y;
        } else {
            be = x;
        }

        if (be <= 0) {
            be = 1;
        }
        opts.inSampleSize = be; // 设置缩放倍数

        bitmap = BitmapFactory.decodeFile(fromPicUrl, opts); // 读取缩放后的图片

        srcWidth = bitmap.getWidth(); // 取得缩放后的长度
        srcHeight = bitmap.getHeight(); // 取得缩放后的宽度

        float scaleWidth = 0; // 定义截取的固定长度
        float scaleHeight = 0; // 定义截取的固定宽度
        if (srcWidth > srcHeight) {
            scaleWidth = (float) width / srcWidth; // 按固定大小缩放 sWidth 写多大就多大
            scaleHeight = (float) height / srcHeight;
        } else {
            scaleWidth = (float) height / srcWidth; // 按固定大小缩放 sWidth 写多大就多大
            scaleHeight = (float) width / srcHeight;
        }

        if (scaleHeight != 1.0 && scaleWidth != 1.0) {// 排除手机拍出来的就是320*240的
            Matrix matrix = new Matrix(); // 定义图片的矩阵对象
            matrix.postScale(scaleWidth, scaleHeight); // 传入缩放的比例值
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, srcWidth, srcHeight, matrix, false);// 取得320*240的图片
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        bitmap.compress(Bitmap.CompressFormat.PNG, 60, baos);
        byte[] pictureByte = baos.toByteArray();

        // 释放bitmap的内存,很重要
        bitmap.recycle();

        // 将bitmap保存为文件
        OutputStream os = null;
        try {
            File file = new File(compress_img_path); // 定义保存照片的文件
            if (!file.exists()) {
                mkdirs(CHEN.img_compress_path, getname(compress_img_path));
            }
            os = new FileOutputStream(file); // 文件输出流
            os.write(pictureByte, 0, pictureByte.length); // 写入文件
        } catch (Exception e) {
            e.toString();
        } finally {
            try {
                if (os != null) {
                    os.close(); // 关闭文件输出流
                }
            } catch (IOException e) {
                e.toString();
            }
        }
    }


    /**
     * 分割字符串,得到不包含路径的文件名
     */
    public static String getname(String str) {
        String name = "";
        String[] ss = str.split("/");
        name = ss[ss.length - 1];
        return name;
    }


    /**
     * 创建文件夹
     */
    public static File mkdirs(String path, String name) {
        File file = new File(path);
        if (!file.exists()) {
            try {
                file.mkdirs();
            } catch (Exception e) {
                return null;
            }
        }
        file = createNewFile(path + "/" + name);
        return file;
    }

    /**
     * 创建文件
     */
    public static File createNewFile(String path) {
        File file = new File(path);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                return null;
            }
        }
        return file;
    }
}

3、主代码


import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.chen.customviewdemo.listener.PopSelectListener;
import com.chen.customviewdemo.utils.CHEN;
import com.chen.customviewdemo.utils.FileHelper;
import com.chen.customviewdemo.utils.Utils;
import com.chen.customviewdemo.view.PhotoFromSelectPop;

import java.io.File;

/**
 * 拍照,并压缩图片
 */
public class MainActivity_21_Photo_Compress_Img extends BaseActivity implements View.OnClickListener, PopSelectListener {

    ImageView iv_image;
    TextView result_url_tv;
    TextView result_url_tv_2;
    TextView photo_src_size;
    TextView photo_compress_size;
    TextView show_tv_21;

    PhotoFromSelectPop photoFromSelectPop;

    String url;
    String imageName;

    String compress_url;

    @Override
    void initview() {
        setContentView(R.layout.activity_main_21);

        iv_image = (ImageView) findViewById(R.id.iv_image);
        result_url_tv = (TextView) findViewById(R.id.result_url_tv);
        result_url_tv_2 = (TextView) findViewById(R.id.result_url_tv_2);
        photo_src_size = (TextView) findViewById(R.id.photo_src_size);
        photo_compress_size = (TextView) findViewById(R.id.photo_compress_size);
        show_tv_21 = (TextView) findViewById(R.id.show_tv_21);

        iv_image.setOnClickListener(this);
        show_tv_21.setOnClickListener(this);

        File file = new File(CHEN.img_path);
        if (!file.exists()) {
            try {
                file.mkdirs();
                Toast.makeText(this, "路径创建成功", Toast.LENGTH_SHORT).show();
            } catch (Exception e) {
                Toast.makeText(this, "路径创建失败", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.iv_image:

                photoFromSelectPop = new PhotoFromSelectPop(this);
                photoFromSelectPop.initPopupWindow(this);

                break;
            case R.id.show_tv_21:
                //TODO
                //点击显示结果。这只是demo,没有做太多判断,不要故意报空指针。拍完照以后,等3秒左右再点击

                result_url_tv.setText(url);

                File file = new File(url);

                photo_src_size.setText("图片大小==KB==" + Utils.getNumAccuracy_2(file.length() / 1024f) + "---图片大小==MB==" + Utils.getNumAccuracy_2(file.length() / (1024f * 1024f)));

                //压缩
                result_url_tv_2.setText(compress_url);

                File compress_file = new File(compress_url);
                photo_compress_size.setText("图片大小==KB==" + Utils.getNumAccuracy_2(compress_file.length() / 1024) + "---图片大小==MB==" + Utils.getNumAccuracy_2(compress_file.length() / (1024f * 1024f)));


                break;
        }

    }

    @Override
    public void popSelect(int flag) {

        switch (flag) {
            case 0:

                Toast.makeText(this, "从相册选取", Toast.LENGTH_SHORT).show();

                break;

            case 1:
                //拍照
                imageName = "/" + System.currentTimeMillis() + ".jpg";
                Intent intent_photo = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intent_photo.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(CHEN.img_path, imageName)));
                startActivityForResult(intent_photo, 1002);
                break;

        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode != 0) {
            url = CHEN.img_path + imageName;
            if (!TextUtils.isEmpty(url)) {

                //开一个子线程去处理压缩。这是因为,压缩会因为一些原因先执行。即:拍照结束后,点击确认按钮,会停一下,才跳转回自己的界面。开了子线程去处理压缩,会让跳转变的流畅一点
                new Thread() {
                    public void run() {
                        //压缩
                        compress_url = FileHelper.checkFileSize(url);
                    }
                }.start();

            }
        } else {
            result_url_tv.setText("没有拍照,返回");
        }
        super.onActivityResult(requestCode, resultCode, data);
    }
}



以上是关于手机拍照及简单的图片压缩的主要内容,如果未能解决你的问题,请参考以下文章

html + js 实现图片上传,压缩,预览及图片压缩后得到Blob对象继续上传问题

vue 移动端拍照压缩base64格式上传

Android 图片选择(ImageSelector) (拍照,裁剪,压缩,查看)

vuejs开发组件分享之H5图片上传压缩及拍照旋转的问题处理

Js利用Canvas实现图片压缩

移动端图片上传旋转压缩的解决方案