Android 图片裁剪

  • 前言
  • 正文
    • 一、创建并配置项目
    • 二、权限申请
    • 三、获取图片Uri
    • 四、图片裁剪
    • 五、源码
  • 尾声

运行效果图

前言

  图片裁剪是对图片进行区域选定,然后裁剪选定的区域,形成一个图片,然后再对这个图片进行压缩,最终返回结果图片。

正文

  从上面的描述来看貌似是挺简单的是吧,不过实际操作起来就没有那么简单了,下面先来看看简单的实现方式,就是Android自带的裁剪。

一、创建并配置项目

我们依然从创建项目开始讲起,这虽然有一些繁琐,但无疑可以让每一个Android开发者看懂。创建一个名为PictureCroppingDemo的项目。

创建好之后,在app的build.gradle添加如下代码,有两处

 //JDK版本compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}
 //  google权限管理框架implementation 'pub.devrel:easypermissions:3.0.0'//热门强大的图片加载器implementation 'com.github.bumptech.glide:glide:4.11.0'annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

添加位置如下图所示:

然后打开AndroidManifest.xml,在里面添加两个权限

 <!--读写外部存储--><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

这两个权限在Android6.0及以上版本属于危险权限,需要动态申请,下面来写权限申请的代码吧。

二、权限申请

首先在MainActivity中重写这个onRequestPermissionsResult方法。这个方法属于Android原生的权限请求返回,下面来看它的具体内容:

 /*** 权限请求结果* @param requestCode 请求码* @param permissions 请求权限* @param grantResults 授权结果*/@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);// 将结果转发给 EasyPermissionsEasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}

EasyPermissions就是刚才在build.gradle中添加的依赖库,然后写一个权限请求的方法。

 @AfterPermissionGranted(9527)private void requestPermission(){String[] param = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};if(EasyPermissions.hasPermissions(this,param)){//已有权限showMsg("已获得权限");}else {//无权限 则进行权限请求EasyPermissions.requestPermissions(this,"请求权限",9527,param);}}

这个requestPermission()方法上面有一个注解,这个注解是什么意思嗯呢,就是权限通过后再调用一次这个方法。然后看方法里面做了什么,定义了一个字符串数组,里面有两个权限,都是在AndroidManifest.xml中配置过的,实际上这两个权限在一个权限组里面,一个权限组只有有一个权限通过则表示整组权限通过,因此你只需要放置一个权限就好了,我这么写是为了让你更清楚一些。然后是一个判断,通过这框架去判断当前的权限是否以获取,是则进行后续操作,我这里是弹一个Toast,方法也很简单。

 /*** Toast提示* @param msg 内容*/private void showMsg(String msg){Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();}

如果没有权限则通过下面这行代码去请求权限

EasyPermissions.requestPermissions(this,"请求权限",9527,param);

这里的9527其实是一个请求码,它需要与注解中的对应,只有这样它在权限授予之后才会再次调用这个方法做检测。更规范的写法是定于一个全局变量,然后替换这个9527,比如这样

 /*** 外部存储权限请求码*/public static final int REQUEST_EXTERNAL_STORAGE_CODE = 9527;

然后修改对应的地方即可,如下图所示:

最终记得在onCreate中调用这个requestPermission()方法。下面运行一下:

三、获取图片Uri

在上面我们已经获取到了权限,下面就来获取这个图片的Uri,然后通过图片Uri显示这个图片。

首先修改布局activity_main.xml

<?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=".MainActivity"><ImageViewandroid:id="@+id/iv_picture"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_marginBottom="24dp"android:onClick="openAlbum"android:text="打开相册" /></RelativeLayout>

很简单的布局,这里唯一要说的就是这个onClick=“openAlbum”,如果你的按钮不需要进行设置的话,单个按钮的点击事件这样写更简洁一些,你会看到这个地方有一条红线,这需要到Activity中去写这个方法,你可以通过快捷键去生成这个方法。鼠标点击这个划红线的地方,然后Alt + Enter,下面会弹出一个窗口,第二项就是说在MainActivity中创建openAlbum方法。这种方式在Fragment中并不是适用,请注意。

然后你就会在MainActivity中看到这样的方法,请注意一点,这个方法名与你onClick中的值必须要一致。

 /*** 打开相册*/public void openAlbum(View view) {}

下面来写打开相册的方法。这里同样的需要一个请求码,去打开相册,然后通过返回的结果去读取图片的uri,定义一个请求码

 /*** 打开相册请求码*/private static final int OPEN_ALBUM_CODE = 100;

然后在修改openAlbum方法,代码如下:

 /*** 打开相册*/public void openAlbum(View view) {Intent intent = new Intent();intent.setAction(Intent.ACTION_PICK);intent.setType("image/*");startActivityForResult(intent, OPEN_ALBUM_CODE);}

注意这里使用了startActivityForResult,则需要获取返回值。重写onActivityResult方法。

 /*** 返回Activity结果** @param requestCode 请求码* @param resultCode  结果码* @param data        数据*/@Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);}

这里先获取相册中的图片显示到Activity中,刚才在activity_main.xml中的ImageView控件就派上用场了。

 //图片private ImageView ivPicture;

然后在onCreate中绑定xml的id。下面你再使用这个ivPicture就不会报空对象了。

 ivPicture = findViewById(R.id.iv_picture);

然后回到onActivityResult方法,修改代码如下:

 @Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == OPEN_ALBUM_CODE && resultCode == RESULT_OK) {final Uri imageUri = Objects.requireNonNull(data).getData();//显示图片Glide.with(this).load(imageUri).into(ivPicture);}}

这里加了一个判断用于检测是否为打开相册之后的返回与返回是否成功。RESULT_OK是Activity中自带的。

然后在获取数据时判空处理一下再赋值给一个Uri变量,然后通过Glide框架加载这个Url显示在刚才的ivPicture上。代码写好了,下面运行一下:


嗯,图片显示出来了,图片的url也拿到了,下面该做这个图片的剪裁了。

四、图片裁剪

既然是调用Android系统的图片裁剪,那么自然也和打开系统相册差不多,依然是先创建一个请求码:

 /*** 图片剪裁请求码*/public static final int PICTURE_CROPPING_CODE = 200;

然后写一个裁剪的方法。

 /*** 图片剪裁** @param uri 图片uri*/private void pictureCropping(Uri uri) {// 调用系统中自带的图片剪裁Intent intent = new Intent("com.android.camera.action.CROP");intent.setDataAndType(uri, "image/*");// 下面这个crop=true是设置在开启的Intent中设置显示的VIEW可裁剪intent.putExtra("crop", "true");// aspectX aspectY 是宽高的比例intent.putExtra("aspectX", 1);intent.putExtra("aspectY", 1);// outputX outputY 是裁剪图片宽高intent.putExtra("outputX", 150);intent.putExtra("outputY", 150);// 返回裁剪后的数据intent.putExtra("return-data", true);startActivityForResult(intent, PICTURE_CROPPING_CODE);}

图片裁剪需要用到uri,再上面打开相册返回时就已经拿到了uri,那么下面修改onActivityResult方法。

 @Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == OPEN_ALBUM_CODE && resultCode == RESULT_OK) {//打开相册返回final Uri imageUri = Objects.requireNonNull(data).getData();//图片剪裁pictureCropping(imageUri);} else if (requestCode == PICTURE_CROPPING_CODE && resultCode == RESULT_OK) {//图片剪裁返回Bundle bundle = data.getExtras();if (bundle != null) {//在这里获得了剪裁后的Bitmap对象,可以用于上传Bitmap image = bundle.getParcelable("data");//设置到ImageView上ivPicture.setImageBitmap(image);}}}

在打开相册返回之后调用pictureCropping方法,传入图片url,然后会启动系统剪裁,剪裁后通过返回数据数据设置到ImageVIew控件上。注意剪裁后就不再是uri了,而是Bitmap。运行一下:

可以看到系统的剪裁并不是很彻底,gif中虽然演示的剪裁时是一个圆形,但实际上剪裁的是一个正方形的,这其实和Android系统版本及设置的参数有关系。我在荣耀8和荣耀20i上运行都是这样的,对应的版本是8.0和10.0,效果基本一致。那么下面修改一下参数试试看,如下图我修改了宽高比例和剪裁后的宽高。

再运行一下:

可以看到通过该参数真的就不一样了不是吗?

但是有一些朋友想要圆形的剪裁,那么这里有一个问题你要弄清楚,你要真的还是假的,真的圆形,那么肯定是需要剪裁后重新生成的,而假的圆形就很好办了,首先我们改回刚才的参数,那么在我的是手机上就还是这样的圆形剪裁框,而我只要让他显示出来是一个圆形,你就会以为你是剪裁成功了,当然这都是忽悠用户的好办法,下面来实践一下。这个可以通过外力来解决,圆形图片很多方式能做到,比如第三方框架、自定义View等。

还记得刚才用过的Glide吗?创建requestOptions对象

 /*** Glide请求图片选项配置*/private RequestOptions requestOptions = RequestOptions.circleCropTransform()//圆形剪裁.diskCacheStrategy(DiskCacheStrategy.NONE)//不做磁盘缓存.skipMemoryCache(true);//不做内存缓存

然后在剪裁图片的返回中设置图片

 Glide.with(this).load(image).apply(requestOptions).into(ivPicture);


运行一下:

五、源码

源码地址:PictureCroppingDemo
CSDN资源地址:PictureCroppingDemo.zip

尾声

OK,就到这里了。我是初学者-Study,山高水长,后会有期。
此项目并不一定适配所有机型和Android版本,要根据实际情况就改动才行。

Android 图片裁剪 (附源码)相关推荐

  1. Android植物大战僵尸附源码

    本文介绍cocos2d-android实现的Android植物大战僵尸,最后附源码 内容介绍: 一.游戏最原始的开发框架. 主要会介绍 a)  SurfaceView+SurfaceHolder.Ca ...

  2. Android 小項目之---Iphone拖动图片特效 (附源码)

    曾经被Iphone用手指在屏幕上滑来滑去拖动图片的操作方式吸引吗?在Android里头,这并不是什么难事. 所需要的技术点如下:Android.content.Context .Android.wid ...

  3. Android 图片框架原理——Glide源码分析

    目录 前言 一.With() 二.load() 三.into() 1. buildImageViewTarget() 2.关注1 :buildRequest 构建 3.关注2:runRequest 执 ...

  4. python自动下载安装软件_30行Python代码从百度自动下载图片(内附源码和exe程序)...

    只需要30行代码就可以从百度自动下载图片 大家好,我是行哥,一个专门教小学生撸Python的编程老师(小学生都能学会的编程) 这里行哥想问大家三个问题 : - 你还在为批量下载表情包发愁吗? - 你还 ...

  5. python玩王者荣耀皮肤_python 王者荣耀皮肤高清图片下载 附源码

    本帖最后由 你isbest 于 2018-3-20 16:33 编辑 最近在学python ,用python做了一个王者荣耀的皮肤高清图片的下载工具,发给大家这个是从官网下载一个json文件,所以是实 ...

  6. python使用多线程进行爬豆瓣电影top250海报图片,附源码加运行结果

    使用多线程进行爬豆瓣电影top250海报图片 # -- coding: UTF-8 -- import time import requests import urllib.request from ...

  7. python3APP爬虫--爬取王者荣耀英雄图片(附源码)

    文章目录 一.准备工作 1.工具 二.思路 1.整体思路 2.爬虫思路 三.获取数据 1.抓包 2.分析json 四.撰写爬虫 五.得到数据 六.总结 之前有写过抖音app用户信息爬虫,因为当时是第一 ...

  8. H5微信自定义分享图文链接(设置标题+简介+图片)——附源码

    1. 最近突然发现微信"卡片式"分享链接变成了如下形式: 原来的是这样的: 后来也解决了,原来是部署域名换了,微信公众号的相关配置没有改造成的.微信的其他域名都可以写多个,唯独服务 ...

  9. VC++屏幕捕获并保存成图片(附源码)

    目录 1.屏幕捕获(截取桌面) 2.将内存中的位图保存成图片文件 3.完整功能的屏幕截图

  10. 【Java项目】讲讲我用Java爬虫获取LOL英雄数据与图片(附源码)

最新文章

  1. C#从SQL server数据库中读取l图片和存入图片
  2. 华为最强自研NPU问世,麒麟810“抛弃”寒武纪
  3. android程序贴吧,【Android 教程总结贴】归纳所有android贴
  4. 修改Visual Studio 2010帮助位置
  5. CentOS 中使用yum时常见的一种提示信息
  6. 【Python】 list dict str
  7. Java使用JAX-WS来写webservice时 Unable to create JAXBContext
  8. ORB特征匹配(python)
  9. Linux多进程的应用
  10. 顶级Linux发行版(10)——Gentoo Linux [转]
  11. 中职计算机英语课件ppt,语文版中职英语(基础模块 上册)Unit 7《Computers》ppt课件1.ppt...
  12. 转:Patch打补丁学习笔记
  13. C#直接调用IE打开指定的网页文件
  14. (爱斯维尔期刊:遇到问题已解决) 使用elsarticle-harv的style引文格式时报错 mand\Nat@force@numbers{}\NAT@force@numbers
  15. 一个立体感的按钮样式
  16. 微信小程序中进行地图导航
  17. ClassName::class
  18. 大数据Hive其实一点都不难,从入坑到放弃?不存在的
  19. Domain Adaptation for Object Detection using SE Adaptors and Center Loss 论文翻译
  20. 软件测试初学者精华(一)

热门文章

  1. 第08课时_三极管恒流源电路
  2. 好消息: 《微信商城开发实战》 已经由电子工业出版社出版发行啦
  3. [分享] 冒险岛079私服搭建
  4. (转)ArcGIS中利用“行政单…
  5. 企业实施办公系统OA可能存在哪些问题?
  6. 第十一周的html学习(w3cshool)
  7. 编写Java程序,使用JTable表格组件展现人员信息列表
  8. 常用的电子书下载网络
  9. Socket长连接和短连接
  10. python网络编程培训