Fresco 二三事:图片处理之旋转、缩放、裁剪切割图片

关于Fresco加载图片的处理,例如旋转、裁剪切割图片,在官方文档也都有提到,只是感觉写的不太详细,正好最近项目里有类似需求,所以分享一些使用小tip,后面的朋友就不用再走弯路浪费时间了。(测试图片分辨率1200*800)

原图:

###旋转图片

/*** 旋转图片** @param rotate ,例如:RotationOptions.ROTATE_90*/private void rotate(SimpleDraweeView img, int rotate) {RotationOptions rotationOptions = RotationOptions.forceRotation(rotate);ImageRequest build = ImageRequestBuilder.newBuilderWithSource(getUriForFresco(this, R.mipmap.test_img)).setRotationOptions(rotationOptions).build();PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder().setImageRequest(build).build();mImageView.setController(controller);}
复制代码

使用效果:

###监听图片下载 首先构造监听器:

//监听图片下载进度,这里只重写了onFinalImageSet,当图片下载完成时获得图片宽高等信息
ControllerListener controllerListener = new BaseControllerListener<ImageInfo>() {@Overridepublic void onFinalImageSet(String id, com.facebook.imagepipeline.image.ImageInfo imageInfo, Animatable animatable) {int viewWidth = imageInfo.getWidth();int viewHeight = imageInfo.getHeight();Toast.makeText(MainActivity.this, viewWidth + "--" + viewHeight, Toast.LENGTH_SHORT).show();}};
复制代码
/*** 获得图片宽高** @param controllerListener 图片下载监听器*/
private void getImageInfo(ControllerListener<? super ImageInfo> controllerListener) {PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder().setControllerListener(controllerListener).setUri(getUriForFresco(this, R.mipmap.test_img)).build();mImageView.setController(controller);
}
复制代码

###如果我想要1:1在手机端展示呢? 我首先想到的是1:1按照图片的尺寸设置SimpleDraweeView的宽高并设置缩放方式为fitXY,但是果不其然,view超出屏幕的部分是无效的。

###裁剪切割图片

既然view超出屏幕无效,那就曲线救国,让图片超出屏幕部分不显示在view里就好了。 裁剪图片首先要写一个processor类:

/*** 切割图片processor类* 四个成员变量和createBitmap时的参数一致,即起点的X/Y坐标、要裁剪的宽高。因为项目里还涉及到缩放,所以我调整了下参数设成百分比方便换算*/
public class CutProcess extends BasePostprocessor {private float mBeginXPercent;private float mBeginYPercent;private float mCutWidthPercent;private float mCutHeightPercent;public CutProcess(float beginXPercent, float beginYPercent, float cutWidthPercent, float cutHeightPercent) {this.mBeginXPercent = beginXPercent;this.mBeginYPercent = beginYPercent;this.mCutWidthPercent = cutWidthPercent;this.mCutHeightPercent = cutHeightPercent;}@Overridepublic CloseableReference<Bitmap> process(Bitmap sourceBitmap,PlatformBitmapFactory bitmapFactory) {int viewWidth = sourceBitmap.getWidth();int viewHeight = sourceBitmap.getHeight();int beginx = (int) (mBeginXPercent * viewWidth);int beginy = (int) (mBeginYPercent * viewHeight);int width = (int) (mCutWidthPercent * viewWidth);int height = (int) (mCutHeightPercent * viewHeight);CloseableReference<Bitmap> bitmapRef = bitmapFactory.createBitmap(sourceBitmap, beginx, beginy, width, height);return CloseableReference.cloneOrNull(bitmapRef);}
}
复制代码

然后在ImageRequest里setProcessor:

/*** 裁剪图片* @param processor*/private void cutPic(BasePostprocessor processor) {ImageRequest build = ImageRequestBuilder.newBuilderWithSource(getUriForFresco(this, R.mipmap.test_img)).setPostprocessor(processor).build();PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder().setImageRequest(build).build();mImageView.setController(controller);}
复制代码

调用方法:

mImageView.setLayoutParams(new RelativeLayout.LayoutParams(600, 400));
CutProcess cutProcess = new CutProcess(0, 0, 0.5f, 0.5f);
cutPic(cutProcess);
复制代码

图片是1200800的,这里设置view的宽高为600400,可以看到图片成功裁剪只保留原图左上四分之一。通过设置view宽高,配合裁剪图片,即可达到1:1显示的效果。

###旋转+裁剪 如果是要旋转90度后再裁剪呢?那还不简单,直接在裁剪的基础上,在ImageRequest里调用旋转方法不就好了。

/*** 旋转+裁剪图片* @param processor*/private void rotateAndcutPic(BasePostprocessor processor, int rotate) {RotationOptions rotationOptions = RotationOptions.forceRotation(rotate);ImageRequest build = ImageRequestBuilder.newBuilderWithSource(getUriForFresco(this, R.mipmap.test_img)).setPostprocessor(processor).setRotationOptions(rotationOptions).build();PipelineDraweeController controller = (PipelineDraweeController) Fresco.newDraweeControllerBuilder().setImageRequest(build).build();mImageView.setController(controller);}
复制代码

然后调用:

//例如我需要旋转90度且宽度不变,高度方向裁剪掉一半(即保留(0,0)-(1200,400))
mImageView.setLayoutParams(new RelativeLayout.LayoutParams(400, mScreenHeight));
CutProcess cutProcess = new CutProcess(0, 0, 1f, 0.5f);
rotateAndcutPic(cutProcess, RotationOptions.ROTATE_90);
复制代码

然而得到的并不是我们想要的

可以看到得到的是左半边(0,0)-(600,800)的图,即宽度方向被裁剪掉一般,高度方向不变,明明我在cutProcess里是设置宽度方向不变,高度方向裁剪50%,但是因为旋转了90度,结果却正好相反。难道是因为旋转90度后横纵方向也发生改变?那调换一下横纵方向的切割比例试试看:

CutProcess cutProcess = new CutProcess(0, 0, 0.5f, 1f);
rotateAndcutPic(cutProcess, RotationOptions.ROTATE_90);
复制代码

可以看到,调换横纵切割比例后,却得到的是下半边(0,400)-(1200,800)。还是不正确,难道是原点也改变了?再测试一下,如果要裁剪后保留右下四分之一(600,400)-(1200,800)区域,正常无旋转的情况下是这样的:

mImageView.setLayoutParams(new RelativeLayout.LayoutParams(600, 400));
CutProcess cutProcess = new CutProcess(0.5f, 0.5f, 0.5f, 0.5f);
rotateAndcutPic(cutProcess, RotationOptions.NO_ROTATION);
复制代码

但如果旋转270度后,同样代码得到的结果却是这样的:

看到这里我们就清楚了,旋转图片后,其实(0,0)点,也就是所谓的原点也随之变换。默认情况下,原点是(0,0),顺时针旋转90度后,原点就变成了(0,800),以此类推旋转180度原点为(1200,800),旋转270度原点为(1200,0)(和旋转后的图片的左上角相对应)。虽然是在构建ImageRequest时同时传入旋转和裁剪参数的,但实际上可以看作是先完成了旋转,然后在旋转后的基础上,以屏幕的左上角为原点,左上角往右为x正方向,左上角往下为y正方向。

小试牛刀一下,旋转270度后,想要裁剪后只保留原图的左上四分之一(0,0)-(600,600),那推测就应该是(0, 0.5f, 0.5f, 0.5f)。

mImageView.setLayoutParams(new RelativeLayout.LayoutParams(400, 600));
CutProcess cutProcess = new CutProcess(0, 0.5f, 0.5f, 0.5f);
rotateAndcutPic(cutProcess, RotationOptions.ROTATE_270);
复制代码

Bingo!推测正确。

旋转+裁剪就是这个原点的变换要注意下。另外看代码里的几个方法,裁剪、旋转、获得宽高等,有没有觉得老是要重复写PipelineDraweeController、ImageRequest的代码好麻烦啊。其实裁剪、旋转等方法无非也就是添加一个参数,类似这种可变参数的复杂类的构造可以使用Builder模式封装一下。封装代码就不贴在这里了。demo下载地址

//Builder模式封装后
new FrescoBuilder(mImageView, getUriForFresco(this, R.mipmap.test_img)).cutPic(0f, 0.5f, 0.5f, 0.5f) //裁剪.setRotate(RotationOptions.ROTATE_270) //旋转.setControllerListener(controllerListener) //设置监听.build();
复制代码

使用Matrix实现

继承SimpleDraweeView自定义控件,使用Matrix实现旋转缩放:

public class MyFresco extends SimpleDraweeView {private Matrix mMatrix;private float mScaleX = 1f;private float mScaleY = 1f;private int mViewWidth = -1;private int mViewHeight = -1;private RectF mDisplayRect = new RectF();private int mDegree = -1;public MyFresco(Context context, GenericDraweeHierarchy hierarchy) {super(context, hierarchy);init();}public MyFresco(Context context) {super(context);init();}public MyFresco(Context context, AttributeSet attrs) {super(context, attrs);init();}public void setViewInfo(int width, int Height) {mViewWidth = width;mViewHeight = Height;}private void init() {mMatrix = new Matrix();mMatrix.postScale(mScaleX, mScaleY);}/*** 缩放* @param scaleX 缩放倍数*/public void setScale(float scaleX, float scaleY) {mScaleX = scaleX;mScaleY = scaleY;mMatrix.postScale(scaleX, scaleY);invalidate();}/*** 旋转* @param degree 角度*/public void rotate(int degree) {if (mDegree == -1) {mDegree = degree;if (mDegree != 0) {mMatrix.postRotate(degree);invalidate();if (mDegree == 90) {//旋转后图片超出边界,所以要再做平移mMatrix.postTranslate(getRectWidth(), 0);} else if (mDegree == 180) {mMatrix.postTranslate(getRectWidth(), getRectHieght());} else if (mDegree == 270) {mMatrix.postTranslate(0, getRectHieght());}}} else {mDegree += degree;mMatrix.postRotate(degree); //getRectWidth是旋转后的widthinvalidate();mMatrix.postTranslate(getRectWidth(), 0);}invalidate();}/*** 还原设置*/public void reset() {mScaleX = 1f;mScaleY = 1f;mMatrix = new Matrix();mMatrix.setScale(mScaleX, mScaleY);mViewWidth = -1;mViewHeight = -1;mDegree = -1;}/*** 获得旋转后超出边界的高度* @return*/public float getRectHieght() {RectF displayRect = getDisplayRect(mMatrix);if (displayRect != null) {return displayRect.height();} else {return -1;}}/*** 获得旋转后超出边界的宽度* @return*/public float getRectWidth() {RectF displayRect = getDisplayRect(mMatrix);if (displayRect != null) {return displayRect.width();} else {return -1;}}private RectF getDisplayRect(Matrix matrix) {if (mViewWidth == -1 || mViewHeight == -1) {return null;}mDisplayRect.set(0.0F, 0.0F, mViewWidth, mViewHeight);getHierarchy().getActualImageBounds(mDisplayRect);//将matrix映射到rectfmatrix.mapRect(mDisplayRect);return mDisplayRect;}@Overrideprotected void onDraw(Canvas canvas) {int save = canvas.save();canvas.concat(mMatrix);super.onDraw(canvas);canvas.restoreToCount(save);}
}复制代码

就是酱~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/539808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

老年人计算机应用基础,国开电大老年心理健康作业一参考答案

题目1.脑功能衰退明显的症状是( )。A. 记忆力衰退B. 皮肤老化C. 孤独感强D. 感知觉能力的退化【答案】&#xff1a;记忆力衰退题目2.下列哪项不属于老年人的特点&#xff1a;( )。A. 肺功能下降B. 体重下降C. 视野狭窄D. 嗜睡【答案】&#xff1a;嗜睡题目3.下列不是诊断老年…

家装强电弱电布线图_关于你不知道的弱电改造详解 提早了解好做准备

在我们的日常生活中&#xff0c;没有一处是不用电的。洗衣、做饭、看电视&#xff0c;这些我们生活中看起来平淡无奇的小事&#xff0c;离开电却难以为继。今天&#xff0c;装一网为大家介绍弱电改造&#xff0c;很多业主不知道弱电改造是什么意思&#xff0c;也不知道弱电改造…

SecureCRT配置前--Linux网卡设置

在用SecureCRT连接Linux的时候&#xff0c;需要设置Linux的网卡信息。 1、输入命令&#xff1a;setup&#xff0c;弹出配置&#xff0c;选择Network configuration&#xff0c;配置网络 2、选择device configuration 配置网卡 3、选择eth0&#xff0c;第一块网卡 4、配置eth0网…

创建SQL函数计算员工加班时间

你好&#xff0c;韩老师有个问题请教。我想通过秒计算加班时间。规则为&#xff1a;加班满4小时才算加班&#xff0c;加班时间满8小时为加班一天&#xff0c;加班时间不足4小时不算加班&#xff0c;加班时间大于4小时小于8小时为0.5个加班。我写了一个自定义函数计算但是计算出…

西安石油大学计算机基础考试试题,2017年西安石油大学计算机学院824计算机组成原理考研题库...

一、名词解释1&#xff0e; 异构多核【答案】异构多核处理机内的各个计算内核结构不同&#xff0c;地位不对等。一般多采用“主处理核协处理核”的主从架构。 异构多核处理机的优势在于可以同时发挥不同类型处理机各自的长处来满足不同种类的应用的性能和功耗需求。研宄表明&am…

cdn节点人少延迟高_让你刷剧一直爽,CDN原理是什么

鼠年春节&#xff0c;一个特别的春节。受疫情影响&#xff0c;假期比往年长了一些。这么长时间宅在家中&#xff0c;想必大家除了睡觉&#xff0c;花费时间最多的就是“刷剧”了。今天讲的技术主题就和“刷剧”有关&#xff0c;它是CDN。我们通过观察CDN的技术来看CDN的产业发展…

ping不通Linux系统解决方法

【申明】解决方法有很多&#xff0c;本文不一定全&#xff0c;本文的方法不一定能帮助你 一、常规安装 1、检查windows系统的网络&#xff0c;是公用还是专用&#xff0c;修改网络类型为专用。 2、关闭windows防火墙&#xff0c;杀毒软件防火墙。 3、关闭Linux防火墙&#…

Linux启动或重启网卡【命令】

启动&#xff1a;ifup eth0重启&#xff1a;/etc/init.d/network/restart 等价于 service network restart

图形的装饰教案计算机,《电脑图案设计师》教案教学设计

《电脑图案设计师》教案教学设计《电脑图案设计师》是湖北长江出版集团出版的小学《信息技术》四年级上册第四单元第二次活动的内容。这节课研究的是Windows画图软件中的“翻转/旋转”和“拉伸/扭曲”两条命令。根据我们对学生的了解和教材的分析&#xff0c;认为这两个知识点如…

boot spring 没有父子容器_Spring 系列(二):Spring MVC的父子容器

1.背景在使用Spring MVC时候大部分同学都会定义两个配置文件&#xff0c;一个是Spring的配置文件spring.xml&#xff0c;另一个是Spring MVC的配置文件spring-mvc.xml。在这里给大家抛个问题&#xff0c;如果在spring.xml和spring-mvc.xml文件中同时定义一个相同id的单例bean会…

Linux创建目录【命令】

创建一个hello目录 mkdir /hello -------------------------------------- mkdir 相当于 make directory 相对路径&#xff1a;不从/开始&#xff0c;而是从当前目录开始&#xff0c;例如&#xff1a;data/ ,mnt/zmg绝对路径&#xff1a;从/开始的目录&#xff0c;就叫绝对…

php string常用函数

<?php$a[]a;$a[]b;$a[]C;echo "</br>";/* implode — 将一个一维数组的值转化为字符串说明string implode ( string $glue , array $pieces )string implode ( array $pieces )用 glue 将一维数组的值连接为一个字符串。 参数glue 默认为空的字符串。 pie…

计算机配置的内存的容量为1GB,如果某计算机的内存寻址空间是1GB,那么这台计算机地址总线的线数为()根。A.32B.20C.16D.30 - 试题答案网问答...

相关题目与解析计算机内存的容量大小受到(11)位数的限制。若该总线为20位&#xff0c;可以寻址的内存空间为(12)字节。A&#xff0e;地址某计算机数据总线为8位&#xff0c;地址总线为10位&#xff0c;则CPU可以直接寻址的内存空间范围为______字节。A&#xff0e;28B&#xff…

手术后多久可以做胆摘除_近视手术后多久可以化眼妆?

今天小编就和大家聊聊&#xff0c;做完近视手术后&#xff0c;多久可以画眼妆&#xff1f;很多女生做完手术后&#xff0c;非常关心的一件事情就是多久可以化妆&#xff0c;化妆对手术效果有没有影响&#xff1f;今天&#xff0c;小编就此问题特别咨询了屈光手术专家。专家建议…

Linux创建文件【命令】

在/opt/hello 目录下创建 world.txt 使用命令&#xff1a;touch 文件名 touch world.txt ---------------------------------------- touch “摸”。touch[文件名]&#xff0c;就是摸一下文件&#xff0c;如果文件不存在&#xff0c;就建立新文件。如果存在&#xff0c;就改…

【CentOS 7LAMP架构4】,PHP5和PHP7的安装和配置#171219

2019独角兽企业重金招聘Python工程师标准>>> hellopasswd 安装PHP5 PHP官网www.php.net当前主流版本为5.6/7.1cd /usr/local/srcwget http://cn2.php.net/distributions/php-5.6.30.tar.bz2bzip2 -d php-5.6.30.tar.bz2tar xvf php-5.6.30.tarcd php-5.6.30./config…

Linux删除文件和文件夹【命令】

1、删除文件夹&#xff1a;rm -r /opt/hello 将会删除/opt/hello目录以及其下所有文件、文件夹 2、删除文件&#xff1a;rm -f /opt/hello/world.txt 将会强制删除/opt/hello/world.txt这个文件 使用这个rm 的时候一定要格外小心&#xff0c;linux没有回收站,以至于删除之后…

Linux修改文件内容【命令】

在/opt/hello/world.txt文件中增加一行 hello linux world ! 方法一&#xff1a; 命令是&#xff1a;vi&#xff0c;vim vi 编辑器&#xff0c;相当于记事本&#xff0c;有编辑功能&#xff0c;但较弱 vim 复杂的编辑器&#xff0c;相当于windows的 editplus, notepad 等 …

计算机机房管理具体工作和职责,机房管理

心得体会是指一种读书、实践后所写的感受性文字。体会是指将学习的东西运用到实践中去&#xff0c;通过实践反思学习内容并记录下来的文字。下面是出国留学网小编带来的机房管理工作心得体会范文&#xff0c;欢迎阅读参考。机房管理工作心得体会(一)学校计算机房是信息技术教学…

hadoop中的9000端口代表什么_hadoop服务快速部署

这篇文章记录下针对不同的hadoop版本进行服务部署的过程&#xff0c;希望可以帮到你们安装docker hadoop2.7.0一键部署docker hadoop3.0.0集群(一个master 三个slave)安装docker hadoop 3.2.0 a、docker启动 b、docker compose方式启动安装hadoop 2.7.0版本安装命令docker run …