您的位置:首页 > 移动开发 > Android开发

Android 图片相关整理

2018-07-05 18:53 337 查看

目录介绍

0.思考问题及解决方案

1.加载图片的压缩处理技术

2.网络url图片转换Bitmap保存到本地

2.1 直接通过http请求网络图片通过流转化成Bitmap

2.2 使用第三方库glide将网络图片转化为Bitmap

3.保存bitmap图片到本地文件夹

4.实现带有圆角的图片

4.1 使用glide处理图片圆角的逻辑

4.2 自定义带有圆角的ImageView

5.毫无满仓轮播图背景做高斯模糊

5.1 高斯模糊实现原理

5.2 高斯模糊实现的代码

5.3 高斯模糊可能会造成的崩溃

5.4 高斯模糊参考案例

关于链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.程序员聊天笔记汇总

5.其他汇总

0.思考问题及解决方案

0.1.0 图片压缩的技术是什么,原理如何理解?

0.1.1 为什么保存图片,切割图片圆角需要将图片转化成bitmap?

0.1.2 对于从网络下载图片,可以采用什么方式?为什么glide相比从网络直接请求更加高效?

0.1.3 图片背景滑动高斯模糊的原理是什么,是否影响性能?

0.1.4 bitmap如何避免被回收?如果回收了,怎么避免出现使用bitmap崩溃

0.1.5 为什么设置高斯模糊需要放在子线程中处理,不这样做会有什么影响?

1.加载图片的压缩处理技术

1.1 压缩技术步骤

1.1.1 科学计算图片所需的采样比例

1.1.2 设置图片加载的渲染模式为Config.RGB_565,能降低一半内存

1.1.3 对bitmap进行质量压缩

1.2 代码如下所示

/**
* 根据路径获得突破并压缩返回bitmap用于显示
* @return          Bitmap
*/
public static Bitmap getSmallBitmap(String filePath, int newWidth, int newHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
//设置只解析图片的边界参数,即宽高
options.inJustDecodeBounds = true;
//options.inSampleSize = 2;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize
//科学计算图片所需的采样比例
options.inSampleSize = calculateInSampleSize(options, newWidth, newHeight);
//设置图片加载的渲染模式为Config.RGB_565,能降低一半内存,但是会影响图片质量
options.inPreferredConfig = Bitmap.Config.RGB_565;
// Decode bitmap with inSampleSize set
//关闭标记,解析真实的图片
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
//质量压缩
Bitmap newBitmap = compressImage(bitmap, 500);
if (bitmap != null){
bitmap.recycle();
}
return newBitmap;
}

/**
* 计算图片的缩放值
*/
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}

/**
* 质量压缩
* @param image
* @param maxSize
*/
private static Bitmap compressImage(Bitmap image, int maxSize){
ByteArrayOutputStream os = new ByteArrayOutputStream();
// scale
int options = 80;
// Store the bitmap into output stream(no compress)
image.compress(Bitmap.CompressFormat.JPEG, options, os);
// Compress by loop
while ( os.toByteArray().length / 1024 > maxSize) {
// Clean up os
os.reset();
// interval 10
options -= 10;
image.compress(Bitmap.CompressFormat.JPEG, options, os);
}
Bitmap bitmap = null;
byte[] b = os.toByteArray();
if (b.length != 0) {
bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
}
return bitmap;
}

2.网络url图片转换Bitmap保存到本地

2.1 直接通过http请求网络图片通过流转化成Bitmap

2.1.1 直接通过网络请求将网络图片转化成bitmap

经过测试,请求8张图片,耗时毫秒值174

如果是服务器响应速度一般,耗时需要2秒【正式接口】

/**
* 请求网络图片转化成bitmap
* @param url                       url
* @return                          将url图片转化成bitmap对象
*/
private static long time = 0;
public static Bitmap returnBitMap(String url) {
long l1 = System.currentTimeMillis();
URL myFileUrl = null;
Bitmap bitmap = null;
HttpURLConnection conn = null;
InputStream is = null;
try {
myFileUrl = new URL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setConnectTimeout(10000);
conn.setReadTimeout(5000);
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
conn.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
long l2 = System.currentTimeMillis();
time = (l2-l1) + time;
LogUtils.e("毫秒值"+time);
//保存
}
return bitmap;
}

2.2 使用第三方库glide将网络图片转化为Bitmap

/**
* 请求网络图片转化成bitmap
*/
private static long times = 0;
public static void glideBitmap(Context context,String url){
final long l1 = System.currentTimeMillis();
Glide.with(context)
.load(url)
.asBitmap()
//设置缓存
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource,
GlideAnimation<? super Bitmap> glideAnimation) {
long l2 = System.currentTimeMillis();
times = (l2-l1) + times;
LogUtils.e("毫秒值"+times);
//请求8张图片,耗时毫秒值98
}
});
}

3.保存bitmap图片到本地文件夹

/**
* 保存图片至自定义路径,刷新相册
*/
public static void saveImageToFile(Context context, Bitmap bmp) {
// 首先保存图片,这个路径可以自定义
File appDir = new File(Environment.getExternalStorageDirectory(), "yc");
// 测试由此抽象路径名表示的文件或目录是否存在
if (!appDir.exists()) {
//如果不存在,则创建由此抽象路径名命名的目录
//noinspection ResultOfMethodCallIgnored
appDir.mkdir();
}
// 然后自定义图片的文件名称
String fileName = System.currentTimeMillis() + ".jpg";
// 创建file对象
File file = new File(appDir, fileName);
try {
FileOutputStream fos = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
// 其次把文件插入到系统图库
try {
MediaStore.Images.Media.insertImage(context.getContentResolver(),
file.getAbsolutePath(), fileName, null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 最后通知图库更新
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.parse("file://" + file.getAbsoluteFile()));
context.sendBroadcast(intent);
}

4.实现带有圆角的图片

4.1 使用glide处理图片圆角的逻辑

/**
* 加载带有圆角的矩形图片  用glide处理
*
* @param path   路径
* @param round  圆角半径
* @param resId  加载失败时的图片
* @param target 控件
*/
public static void loadImgByPicassoWithRound(final Context activity, String path,
final int round, int resId, final ImageView target) {
if (path != null && path.length() > 0) {
Glide.with(activity)
.load(path)
.asBitmap()
.placeholder(resId)
.error(resId)
//设置缓存
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new BitmapImageViewTarget(target) {
@Override
protected void setResource(Bitmap resource) {
super.setResource(resource);
RoundedBitmapDrawable circularBitmapDrawable = RoundedBitmapDrawableFactory
.create(activity.getResources(), resource);
//设置绘制位图时要应用的角半径
circularBitmapDrawable.setCornerRadius(round);
target.setImageDrawable(circularBitmapDrawable);
}
});
}
}

4.2 自定义带有圆角的ImageView

使用BitmapShader实现圆形、圆角图片

具体看:https://github.com/yangchong211/YCPaiDian 中的lib\image自定义imageView

5.毫无满仓轮播图背景做高斯模糊

5.1 高斯模糊实现原理

前沿【摘自网络】:在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的。考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是最慢的。但是Android推出RenderScript之后,我们就有了新的选择,测试表明,使用RenderScript的渲染效率和使用C/C++不相上下,但是使用RenderScript却比使用JNI简单地多!

原理步骤如下所示:

a.压缩图片,可以质量压缩,也可以宽高压缩

b.创建RenderScript内核对象

c.创建一个模糊效果的RenderScript的工具对象

d.设置相关参数,具体看代码……

实现思路:先将图片进行最大程度的模糊处理,再将原图放置在模糊后的图片上面,通过不断改变原图的透明度(Alpha值)来实现动态模糊效果。

5.2 高斯模糊实现的代码

5.2.1 设置高斯模糊代码

/**
* 设置模糊背景
*/
private void setBlurBackground(int pos) {
//获取轮播图索引pos处的图片
Integer integer = pagerAdapter.getBitmapHashMap().get(pos);
Resources res = this.getResources();
Bitmap bitmap= BitmapFactory.decodeResource(res, integer);
//压缩图片
final Bitmap image = BitmapUtils.compressImage(bitmap);

if (bitmap != null) {
if (mBlurRunnable != null) {
mIvBlurBackground.removeCallbacks(mBlurRunnable);
}
mBlurRunnable = new Runnable() {
@Override
public void run() {
//压缩图片,宽高缩放
Bitmap blurBitmap = BlurBitmapUtils.getBlurBitmap(
mIvBlurBackground.getContext(), image, 15);
ViewSwitchUtils.startSwitchBackgroundAnim(mIvBlurBackground, blurBitmap);
}
};
mIvBlurBackground.postDelayed(mBlurRunnable, 100);
}
}


5.2.2 RenderScript图片高斯模糊

/**
* RenderScript图片高斯模糊
*/
public class BlurBitmapUtils {

/**
* 建议模糊度(在0.0到25.0之间)
*/
private static final int SCALED_WIDTH = 100;
private static final int SCALED_HEIGHT = 100;

/**
* 得到模糊后的bitmap
* @param context                   上下文
* @param bitmap                    bitmap
* @param radius                    半径
* @return
*/
public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) {
// 将缩小后的图片做为预渲染的图片。
Bitmap inputBitmap = Bitmap.createScaledBitmap(bitmap, SCALED_WIDTH, SCALED_HEIGHT, false);
// 创建一张渲染后的输出图片。
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
// 创建RenderScript内核对象
RenderScript rs = RenderScript.create(context);
// 创建一个模糊效果的RenderScript的工具对象
ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
// 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。
// 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
// 设置渲染的模糊程度, 25f是最大模糊度
blurScript.setRadius(radius);
// 设置blurScript对象的输入内存
blurScript.setInput(tmpIn);
// 将输出数据保存到输出内存中
blurScript.forEach(tmpOut);
// 将数据填充到Allocation中
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}

}


5.2.3 设置高斯模糊背景View动画过渡效果

/**
* 图片背景切换动画帮助类,设置View动画
*/
public class ViewSwitchUtils {

static void startSwitchBackgroundAnim(ImageView view, Bitmap bitmap) {
Drawable oldDrawable = view.getDrawable();
Drawable oldBitmapDrawable ;
TransitionDrawable oldTransitionDrawable = null;
if (oldDrawable instanceof TransitionDrawable) {
oldTransitionDrawable = (TransitionDrawable) oldDrawable;
oldBitmapDrawable = oldTransitionDrawable.findDrawableByLayerId(oldTransitionDrawable.getId(1));
} else if (oldDrawable instanceof BitmapDrawable) {
oldBitmapDrawable = oldDrawable;
} else {
oldBitmapDrawable = new ColorDrawable(0xffc2c2c2);
}

if (oldTransitionDrawable == null) {
oldTransitionDrawable = new TransitionDrawable(new Drawable[]{oldBitmapDrawable, new BitmapDrawable(bitmap)});
oldTransitionDrawable.setId(0, 0);
oldTransitionDrawable.setId(1, 1);
oldTransitionDrawable.setCrossFadeEnabled(true);
view.setImageDrawable(oldTransitionDrawable);
} else {
oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(0), oldBitmapDrawable);
oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(1), new BitmapDrawable(bitmap));
}
oldTransitionDrawable.startTransition(1000);
}
}

5.3 高斯模糊可能会造成的崩溃

5.3.1 崩溃日志

开发回收bitmap引发Canvas: trying to use a recycled bitmap错误处理

5.3.2 抛该异常的原因分析

如果代码已经不再需要使用Bitmap对象了,就可以释放了。释放内存以后,就不能再使用该Bitmap对象了,如果再次使用,就会抛出异常。所以一定要保证不再使用的时候释放。

5.3.3 解决该问题的办法

使用缓存

5.4 高斯模糊参考案例

Android 图片高斯模糊解决方案:https://www.jianshu.com/p/02da487a2f43

关于我的博客

我的个人站点:www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts

简书:http://www.jianshu.com/u/b7b2c6ed9284

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/

开源中国:https://my.oschina.net/zbj1618/blog

泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1

邮箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV

segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Glide Android compress