博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android触摸事件(五)-CropBitmapActivity关于裁剪工具的使用
阅读量:6441 次
发布时间:2019-06-23

本文共 15236 字,大约阅读时间需要 50 分钟。

文件夹

概述

这个Activity是为了裁剪图片的.使用时须要提供裁剪图片的路径,以及图片裁剪后输出的路径.同一时候假设图片存在旋转角度也能够提供,Activity会先将图片的旋转角度处理后再进行裁剪.


传递数据

  • inputPath:被裁剪图片的路径(完整路径)
  • outputPath:图片裁剪后输出的路径(完整路径,包含图片的格式)
  • degree:图片须要旋转的角度

在启动Activity时传递以上数据就可以显示并裁剪图片,图片会终于保存到指定的路径.


裁剪流程

Activity仅仅仅仅是作为一个窗体显示,实际的裁剪工作是由自己定义CropView进行裁剪的.

当中所以有裁剪操作由CropView完毕,可是保存操作须要通过Activity通知CropView进行保存.


其他事项

须要注意的是:

  • 当不存在源图片(inputPath)资源时会载入默认演示样例资源图片.(仅作为demo功能演示样例)
  • 默认载入图片的720像素的缩略图进行裁剪.
  • 裁剪对象理论上能够是不论什么图片对象,可是考虑到内存因此建议仅仅使用缩略图.
  • 保存时默认使用的格式为PNG,在具体使用该Activity时须要改动相应的保存格式.
  • 保存时须要指定图片质量,从0-100,默觉得50(格式为PNG时,设置质量无效)

建议使用PNG格式,由于当裁剪图片有透明背景存在时,裁剪后的图片依旧能够保持图片的透明特性.同一时候裁剪图片即使是JPG也是能够正常显示.


使用方式

直接通过其静态方法调用就可以.

//创建图片输出路径String outputPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/transformBitmap.png";//參数1:Context//參数2:源图片路径,源图片路径为null,使用内置演示样例图片//參数3:裁剪图片输出路径//參数4:图片旋转角度(纠正图片的角度)CropBitmapActivity.startThisActivitySelf(MainActivity.this, null, outputPath, 0);

图片辅助功能

在此Activity中须要使用到两个图片辅助功能.当中一个是载入图片的缩略图从而达到减小内存使用的目的.

另外一个是获取图片的旋转角度并旋转图片.
这两个功能是比較有用的,特别是第一个功能.以下给出这两个功能的源代码.同一时候在后面将会有专门的一篇文章用来收集相似的有用的功能性的代码.欢迎关注.


图片缩略图载入

图片缩略图载入的本质是,获取图片的宽高大小,然后按比例载入出小尺寸的图片,从而达到减小图片占用内存的目的.

关于图片缩略图及相关的能够见另外的文章,后面会使用一个专用类来说明

/** * 载入缩放后的图片 * * @param in        图片流数据 * @param reqSize   预期图片最长边同意的最大值 * @return 返回缩放载入后的图片, 但图片的最大边长度并不一定等于reqSize,仅仅是近似并小于这个值 */public static Bitmap decodeBitmapInScale(String filePath, int reqSize) {    if (TextUtils.isEmpty(filePath) || reqSize <= 0) {        return null;    } else {        BitmapFactory.Options options = new BitmapFactory.Options();        //仅载入图片宽高大小(不载入图片实际二进制数据)        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(filePath, options);        if (reqSize <= 0) {            throw new RuntimeException("预期边长不可小于0");        }        float bmpWidth = options.outWidth;        float bmpHeight = options.outHeight;        float largeSizeInBmp = 0;        int sampleSize = 1;        //记录最大的边        if (bmpWidth > bmpHeight) {            largeSizeInBmp = bmpWidth;        } else {            largeSizeInBmp = bmpHeight;        }        //将最大边与预期的边大小进行比較计算缩放比        if (largeSizeInBmp < reqSize) {            //最大边小于预期,则sampleSize为1            sampleSize = 1;        } else {            //最大边大于预期边            sampleSize = (int) (largeSizeInBmp / reqSize + 0.5);            //计算所得缩放值为2的几倍指数,即求 log2(sampleSize)            double powerNum = Math.log(sampleSize) / Math.log(2);            int tempPowerNum = (int) powerNum;            //将所得指数+1,确保尽可能小于指定值            if (powerNum > tempPowerNum) {                tempPowerNum += 1;            }            //反求sampleSize=2^tempPowerNum            sampleSize = (int) Math.pow(2, tempPowerNum);        }        //完整载入图片        options.inJustDecodeBounds = false;        //图片缩放比        options.inSampleSize = sampleSize;        //图片是否可改动        options.inMutable = true;        return BitmapFactory.decodeFile(filePath, options);    }}

图片旋转

图片旋转角度是基于图片本身记录的信息.假设图片信息中不存在旋转角度,这里也是获取不到的(即使图片本身确实存在旋转的情况).

以上主要是在相机拍照时使用到.部分相机拍照时会自己主动旋转,实际图片显示的角度与拍摄时的角度是不同的,此时就会记录在相片信息中.

但须要读取相片并又一次保存为一个新文件(不作不论什么改动时),图片信息中的旋转角度会被删除,此时也不会再取到不论什么的角度旋转信息.

//读取图片属性:旋转的角度 public static int readPictureDegree(String path) {     int degree = 0;     try {         ExifInterface exifInterface = new ExifInterface(path);         int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);         switch (orientation) {             case ExifInterface.ORIENTATION_ROTATE_90:                 degree = 90;                 break;             case ExifInterface.ORIENTATION_ROTATE_180:                 degree = 180;                 break;             case ExifInterface.ORIENTATION_ROTATE_270:                 degree = 270;                 break;         }     } catch (IOException e) {         e.printStackTrace();     }     return degree; } //旋转图片 public static Bitmap rotatingBitmap(int angle, Bitmap bitmap) {    //旋转图片动作    Matrix matrix = new Matrix();    matrix.postRotate(angle);    System.out.println("angle2=" + angle);    // 创建新的图片    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,            bitmap.getWidth(), bitmap.getHeight(), matrix, true);    return resizedBitmap;}

源代码

JAVA代码

/** * Created by taro on 16/1/11. */public class CropBitmapActivity extends Activity implements View.OnClickListener {
private Button mBtnLeftRotate; private Button mBtnRightRotate; private Button mBtnConfirm; private Button mBtnCancel; private CropView mCropView; Handler mHandler = null; ProgressDialog mDialog = null; Bitmap mPhoto = null; String mFilePath = null; String mOutputPath = null; /** * 启动此Activity * * @param act * @param srcBitmapPath 来源图片的路径 * @param outputPath 裁剪后输出的图片路径 * @param degree 图片旋转了的角度 */ public static void startThisActivitySelf(Activity act, String srcBitmapPath, String outputPath, int degree) { Intent intent = new Intent(act, CropBitmapActivity.class); intent.putExtra("inputPath", srcBitmapPath); intent.putExtra("outputPath", outputPath); intent.putExtra("degree", degree); act.startActivity(intent); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_transform_bitmap); mBtnLeftRotate = (Button) findViewById(R.id.transform_left_rotate_btn); mBtnRightRotate = (Button) findViewById(R.id.transform_right_rotate_btn); mBtnConfirm = (Button) findViewById(R.id.transform_confirm_btn); mBtnCancel = (Button) findViewById(R.id.transform_cancel_btn); mCropView = (CropView) findViewById(R.id.transform_bitmap_cv); mBtnLeftRotate.setOnClickListener(this); mBtnRightRotate.setOnClickListener(this); mBtnConfirm.setOnClickListener(this); mBtnCancel.setOnClickListener(this); //输入地址 mFilePath = getIntent().getStringExtra("inputPath"); //输出地址 mOutputPath = getIntent().getStringExtra("outputPath"); int degree = getIntent().getIntExtra("degree", 0); InputStream in = null; //不存在源图片路径时,载入默认的演示样例图片资源 if (mFilePath == null) { mPhoto = decodeBitmapInScale(getResources(), R.raw.pkq, 720); } else { mPhoto = decodeBitmapInScale(mFilePath, 720); } //存在旋转角度,对图片进行旋转 if (degree != 0) { //旋转图片 Bitmap originalBitmap = rotatingBitmap(degree, mPhoto); //回收旧图片 mPhoto.recycle(); mPhoto = originalBitmap; } mCropView.setImageBitmap(mPhoto); mDialog = new ProgressDialog(this); mDialog.setTitle("正在处理图片..."); mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0x1: mDialog.show(); break; case 0x2: mDialog.dismiss(); finish(); break; case 0x3: mDialog.dismiss(); break; case 0x4: Toast.makeText(CropBitmapActivity.this, msg .getData().getString("toast"), Toast.LENGTH_LONG).show(); break; } } }; } @Override protected void onDestroy() { super.onDestroy(); if (mPhoto != null && !mPhoto.isRecycled()) { mPhoto.recycle(); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.transform_confirm_btn: //显示载入对话框 mHandler.sendEmptyMessage(0x1); new Thread() { @Override public void run() { if (mCropView.restoreBitmap(mOutputPath, Bitmap.CompressFormat.PNG, true, 50)) { setResult(RESULT_OK); mPhoto.recycle(); String toast = "裁剪图片保存到: " + mOutputPath; Bundle data = new Bundle(); data.putString("toast", toast); Message msg = Message.obtain(); msg.what = 0x4; msg.setData(data); mHandler.sendMessage(msg); mHandler.sendEmptyMessageDelayed(0x2, Toast.LENGTH_LONG); } else { //仅取消对话框 mHandler.sendEmptyMessage(0x3); } } }.start(); break; case R.id.transform_cancel_btn: //取消时须要回收图片资源 mCropView.recycleBitmap(); setResult(RESULT_CANCELED); finish(); break; } } /** * 载入缩放后的图片 * * @param filePath 图片路径 * @param reqSize 预期图片最长边同意的最大值 * @return 返回缩放载入后的图片, 但图片的最大边长度并不一定等于reqSize,仅仅是近似并小于这个值 */ public static Bitmap decodeBitmapInScale(String filePath, int reqSize) { if (TextUtils.isEmpty(filePath) || reqSize <= 0) { return null; } else { BitmapFactory.Options options = new BitmapFactory.Options(); //仅载入图片宽高大小(不载入图片实际二进制数据) options.inJustDecodeBounds = true; BitmapFactory.decodeFile(filePath, options); if (reqSize <= 0) { throw new RuntimeException("预期边长不可小于0"); } float bmpWidth = options.outWidth; float bmpHeight = options.outHeight; float largeSizeInBmp = 0; int sampleSize = 1; //记录最大的边 if (bmpWidth > bmpHeight) { largeSizeInBmp = bmpWidth; } else { largeSizeInBmp = bmpHeight; } //将最大边与预期的边大小进行比較计算缩放比 if (largeSizeInBmp < reqSize) { //最大边小于预期,则sampleSize为1 sampleSize = 1; } else { //最大边大于预期边 sampleSize = (int) (largeSizeInBmp / reqSize + 0.5); //计算所得缩放值为2的几倍指数,即求 log2(sampleSize) double powerNum = Math.log(sampleSize) / Math.log(2); int tempPowerNum = (int) powerNum; //将所得指数+1,确保尽可能小于指定值 if (powerNum > tempPowerNum) { tempPowerNum += 1; } //反求sampleSize=2^tempPowerNum sampleSize = (int) Math.pow(2, tempPowerNum); } //完整载入图片 options.inJustDecodeBounds = false; //图片缩放比 options.inSampleSize = sampleSize; //图片是否可改动 options.inMutable = true; return BitmapFactory.decodeFile(filePath, options); } } /** * 载入缩放后的图片 * * @param res * @param resID 资源ID * @param reqSize 预期图片最长边同意的最大值 * @return 返回缩放载入后的图片, 但图片的最大边长度并不一定等于reqSize,仅仅是近似并小于这个值 */ public static Bitmap decodeBitmapInScale(Resources res, int resID, int reqSize) { if (res == null || resID == 0 || reqSize <= 0) { return null; } else { BitmapFactory.Options options = new BitmapFactory.Options(); //仅载入图片宽高大小(不载入图片实际二进制数据) options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resID, options); if (reqSize <= 0) { throw new RuntimeException("预期边长不可小于0"); } float bmpWidth = options.outWidth; float bmpHeight = options.outHeight; float largeSizeInBmp = 0; int sampleSize = 1; //记录最大的边 if (bmpWidth > bmpHeight) { largeSizeInBmp = bmpWidth; } else { largeSizeInBmp = bmpHeight; } //将最大边与预期的边大小进行比較计算缩放比 if (largeSizeInBmp < reqSize) { //最大边小于预期,则sampleSize为1 sampleSize = 1; } else { //最大边大于预期边 sampleSize = (int) (largeSizeInBmp / reqSize + 0.5); //计算所得缩放值为2的几倍指数,即求 log2(sampleSize) double powerNum = Math.log(sampleSize) / Math.log(2); int tempPowerNum = (int) powerNum; //将所得指数+1,确保尽可能小于指定值 if (powerNum > tempPowerNum) { tempPowerNum += 1; } //反求sampleSize=2^tempPowerNum sampleSize = (int) Math.pow(2, tempPowerNum); } //完整载入图片 options.inJustDecodeBounds = false; //图片缩放比 options.inSampleSize = sampleSize; //图片是否可改动 options.inMutable = true; return BitmapFactory.decodeResource(res, resID, options); } } /** * 旋转图片 * * @param angle * @param bitmap * @return Bitmap */ public static Bitmap rotatingBitmap(int angle, Bitmap bitmap) { if (bitmap == null || bitmap.isRecycled()) { return null; } //旋转图片 动作 Matrix matrix = new Matrix(); matrix.postRotate(angle); System.out.println("angle2=" + angle); // 创建新的图片 Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; }}

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" android:orientation="vertical"> <LinearLayout android:id="@+id/transform_menu_lin" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="gone" android:weightSum="2"> <Button android:id="@+id/transform_left_rotate_btn" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="左旋" android:textSize="14sp"/> <Button android:id="@+id/transform_right_rotate_btn" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="右旋" android:textSize="14sp"/> </LinearLayout> <LinearLayout android:id="@+id/transform_operation_lin" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:weightSum="2"> <Button android:id="@+id/transform_cancel_btn" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="取消" android:textSize="14sp"/> <Button android:id="@+id/transform_confirm_btn" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:text="确定" android:textSize="14sp"/> </LinearLayout> <com.henrytaro.ct.ui.CropView android:id="@+id/transform_bitmap_cv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/transform_operation_lin" android:layout_below="@id/transform_menu_lin" android:layout_centerInParent="true"/> </RelativeLayout>

GitHub地址


演示样例GIF

裁剪图片演示样例

你可能感兴趣的文章
SharePoint 2013 安装.net framework 4.5已经存在更高版本的解决方案
查看>>
Windows Server 2003为什么识别不了的移动硬盘
查看>>
1.区块链技术介绍
查看>>
javascript 里面嵌套方法
查看>>
linux 系统安装 mysql
查看>>
Spring Boot Start 打包方式装B指南
查看>>
简单学习tar命令
查看>>
在mesos上安装storm,并且执行wordcount测试程序
查看>>
用 ElementTree 在 Python 中解析 XML
查看>>
gcc的使用简介与命令行参数说明
查看>>
Java中的编码乱码问题
查看>>
android数据库sqlite增加删改查
查看>>
WdatePicker日历控件使用方法
查看>>
js 表单序列化为json对象
查看>>
Week4-作业1:阅读笔记与思考
查看>>
python学习之老男孩python全栈第九期_day008知识点总结
查看>>
python学习之老男孩python全栈第九期_数据库day002知识点总结 —— MySQL数据库day2...
查看>>
SpringMVC基础03——常用注解之@RequestMapping
查看>>
属性动画
查看>>
定时提醒软件-workrave
查看>>