浅谈android中加载高清大图及图片压缩方式(二)

2024-08-27 14:48

本文主要是介绍浅谈android中加载高清大图及图片压缩方式(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  这一讲就是本系列的第二篇,一起来聊下关于android中加载高清大图的问题,我们都知道如果我们直接加载原图的话,一个是非常慢,需要等待一定时间,如果没有在一定的时间内给用户响应的话,将会极大影响用户的体验。另一个是如果你的手机内存小的话,可能会直接崩溃。这也就是直接加载高清原图问题。遇到这些问题很容易想到的一点就是图片压缩,本篇文章也就是讲述图片压缩方式来实现加载高清大图的效果。但是现在问题就来了,通过上篇博客我们知道,手机的分辨率有很多,如何保证我同一张图片在不同分辨率的手机上能适当的压缩比例显示出来呢???有的人就直接压缩小点,那么就可以在不同的多个分辨率的手机上显示出来。但是我们都知道压缩的越小,失真率就越高。很容易理解,大部分我们使用的都是位图,位图有一个特点就是有很多个像素点组成的像素矩阵,当我们压缩图片时就相当于像素点,本来显示这张图片需要720*1280个像素点,现在压缩成320*480个像素点,这么少的像素点不足以显示出原来的效果,最后明显造成图片显示不清楚。所以找到一个合适的压缩比例就显得尤为重要了。

  那我们如何做呢?实现的大致思路如下:我们所谓的压缩实际上就是去设置BItmap中的一个inSampleSize(采样率)属性,通过它实现图片的压缩。怎么样去给inSampleSize属性设置一个合适的值呢??首先因为屏幕的分辨率多样化,然后我的图片要根据不同分辨率来得到不同inSampleSize,这样才会合适显示在我的手机屏幕上。所以需要获得屏幕的高度和宽度,然后再去拿到屏幕高度和宽度。然后用图片的宽度,高度分别去除以屏幕的高度和宽度,最后就得到高度比例和宽度比例。

到这里就会出现两种方法来实现压缩:一种比较繁琐,另一种更直接。

  首先,说第一种压缩方式吧。

由于图片大多数都是位图显示,即具体个数的像素点来显示的,在不同分辨率的手机屏幕显示图片说白就是在不同像素点的总数的屏幕中显示,很容易理解,当我有个很大的图片,所谓很很大的图片 就是总的像素点数很多,并且在低分辨(总的像素点少显示)肯定有问题,只能显示部分,所以需要 根据当前的手机分辨率的大小,来适当压缩图片的大小比例,然后来显示在相应分辨率的屏幕上当我通过某个方式拿到一张图片会有如下几种情况:  图片宽度(ImWidth),图片高度(ImHeight),屏幕宽度(Width),屏幕高度(Height)
        
      1、若图片的宽度大于图片高度(即横向图片),且宽度大于屏幕宽度:Size=ImWidth/Width
      2、若图片的高度大于图片宽度(即纵向图片),且高度大于屏幕高度:Size=ImHeight/Height;
      3、就是根据一个图片压缩比例算法公式:取图片宽度压缩倍数和图片高度的压缩倍数的平均值:Size=(ImWidth/Width+ImHeight/Height)/2;

最后将我们在不同情况下得到的size赋给我们的inSampleSize。

 然后,说第二种,第二种就更直接暴力,直接给出一个公式:

                      inSampleSize=Math.sqrt(widthScaleSize*widthScaleSize+heightScaleSize*heightScaleSize);

这个公式有点像数学上的勾股定理,但是自己想想挺有道理,它这样取这么一个inSampleSize,其实类似就是去对角线的压缩比。

最后再来说一种方式,这个叫图片质量的压缩,就是在我们压缩图片过程,如何尽量保证我们的图片的质量呢??主要是通过Bitmap的compress来实现

质量的压缩的。不妨我们来看下源码是怎么介绍的吧。

    /**
     * Write a compressed version of the bitmap to the specified outputstream.
     * If this returns true, the bitmap can be reconstructed by passing a
     * corresponding inputstream to BitmapFactory.decodeStream(). Note: not
     * all Formats support all bitmap configs directly, so it is possible that
     * the returned bitmap from BitmapFactory could be in a different bitdepth,
     * and/or may have lost per-pixel alpha (e.g. JPEG only supports opaque
     * pixels).
     *
     * @param format   The format of the compressed image
     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
     *                 small size, 100 meaning compress for max quality. Some
     *                 formats, like PNG which is lossless, will ignore the
     *                 quality setting
     * @param stream   The outputstream to write the compressed data.
     * @return true if successfully compressed to the specified stream.
     */

bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos)

它大致的意思是这样的就是将一个Bitmap对象保存在一个确定的输出流中,并且compress会返回一个boolean类型的值,如果返回为true

就会通过一个与之相对应的输入流来重建一个BItmap对象,然后标注了:并不是所有的格式都直接支持这种方式,这样就会造成出来不同尺寸大小BItmap可能

会失去原有图片像素的透明度。力例如JPEG格式图片仅仅支持不透明像素点。还需要注意:就是里面quality参数的介绍:它是这样说的quatily取值范围为:0到100

0代表质量最低,100则代表质量最高,如果是PNG格式的图片的话,忽视了质量值的设置,就会造成图片的失真。

那么有了以上的了解,相信对下面代码的理解更加简单了。

  

package com.mikyou.loadBigImage;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.os.Bundle;
import android.os.Environment;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.ImageView;public class MainActivity extends Activity {private ImageView bigIv;private int Width, Height, ImWidth, ImHeight;//获取屏幕的高度和宽度以及图片的高度和宽度@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getScreenWidthAndHeight();bigIv = (ImageView) findViewById(R.id.big_iv);}public void loadBigImage(View view) {//读取SD卡的状态,并且-判断SD卡是否可用if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//先判断SD卡的状态是否可用,mnt目录shell--->emualted---->0//如果是可用的状态,就读到SD卡的路径,然后将它加载出来//如果图片过大就容易造成图片加载的延迟甚至会造成内存溢出,所以需要对图片做一定的压缩处理BitmapFactory.Options options = new BitmapFactory.Options();String path = Environment.getExternalStorageDirectory() + "/img_big_1.jpg";/*** 思考:如何合理设置inSampleSize来针对不同分辨率的手机,从而得到一个更佳的图片压缩方案呢??* 分析:* 由于图片大多数都是位图显示,即具体个数的像素点来显示的,在不同分辨率的手机屏幕显示图片* 说白就是在不同像素点的总数的屏幕中显示,很容易理解,当我有个很大的图片,所谓很很大的图片* 就是总的像素点数很多,并且在低分辨(总的像素点少显示)肯定有问题,只能显示部分,所以需要* 根据当前的手机分辨率的大小,来适当压缩图片的大小比例,然后来显示在相应分辨率的屏幕上* 当我通过某个方式拿到一张图片会有如下几种情况:*       图片宽度(ImWidth),图片高度(ImHeight),屏幕宽度(Width),屏幕高度(Height)*       一、根据SD卡路径加载图片的大小比例压缩*              1、若图片的宽度大于图片高度(即横向图片),且宽度大于屏幕宽度:Size=ImWidth/Width*              2、若图片的高度大于图片宽度(即纵向图片),且高度大于屏幕高度:Size=ImHeight/Height;*              3、就是根据一个图片压缩比例算法公式:取图片宽度压缩倍数和图片高度的压缩倍数的平均值:Size=(ImWidth/Width+ImHeight/Height)/2;*       二、图片的质量的压缩*       三、根据Bitmap来压缩图片大小比例* *///bitmap=getImageCompress(bitmap);// bitmap= getImageByScaleSize(bitmap);Bitmap bitmap=getImageByScaleSizeByTec(path);bigIv.setImageBitmap(bitmap);}}/*** 图片的质量压缩:* 图片质量的压缩思想大致如下:* 先将一张图片到一个字节数组输出流对象保存,* 然后通过不断压缩数据,直到图片大小压缩到某个具体大小时,然后再把* 字节数组输出流对象作为一个字节数组输入流参数对象传入得到一个字节数组输入流* 最后再将字节数组输入流得到Bitmap对象,最终拿到图片质量压缩后的图片*/public Bitmap getImageCompress(Bitmap bitmap) {ByteArrayOutputStream baos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到字节数组输出流中。int options = 100;while (baos.toByteArray().length / 1024 > 100) {    //循环判断如果压缩后图片是否大于100kb,大于继续压缩baos.reset();//重置baos即清空baosoptions -= 10;//每次都减少10bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中Bitmap bitmap2 = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片return bitmap2;}/*** 根据SD卡路径加载图片的大小比例压缩*/public Bitmap getImageByScaleSize(String path) {int scaleSize =1;//1就表示不压缩BitmapFactory.Options options = new BitmapFactory.Options();/*       options.inJustDecodeBounds=true;//只读取图片的信息,不读取图片的具体数据ImWidth = options.outWidth;ImHeight = options.outHeight;*/getImageWidthAndHeight(path);//得到图片的高度和宽度if (ImWidth > ImHeight && ImWidth > Width) {scaleSize = (int)(ImWidth*1.0f / Width+0.5f);//加0.5是为了四舍五入,取一个很好的精度} else if (ImHeight > ImWidth && ImHeight > Height) {scaleSize = (int)(ImHeight*1.0f / Height+0.5f);} else {//其他情况表示,就是当是横向或者纵向图片时,它的长度和宽度都大于屏幕scaleSize = (int)(ImWidth*1.0f / Width + ImHeight*1.0f / Height+0.5f) / 2;}ba//设置图片的采样率options.inSampleSize = scaleSize;//针对不同的手机分辨率,设置的缩放比也不一样,这里的值可能是不一样的Bitmap bitmap2 = BitmapFactory.decodeFile(path, options);return bitmap2;}//获取当前手机屏幕的高度和宽度private void getScreenWidthAndHeight() {DisplayMetrics metrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(metrics);Width = metrics.widthPixels;Height = metrics.heightPixels;}//得到原图的高度和宽度private void getImageWidthAndHeight(String path) {try {ExifInterface exifInterfece=new ExifInterface(path);ImWidth=exifInterfece.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH,0);ImHeight=exifInterfece.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH,0);} catch (IOException e) {e.printStackTrace();}}/*** 公式法* */public Bitmap getImageByScaleSizeByTec(String path){int scaleSize =1;//1就表示不压缩getImageWidthAndHeight(path);int WidthScaleSize=(int)(ImWidth*1.0f/Width*1.0f+0.5f);int HeightScaleSize=(int)(ImHeight*1.0f/Height*1.0f+0.5f);scaleSize=(int)(Math.sqrt(WidthScaleSize*WidthScaleSize+HeightScaleSize*HeightScaleSize)+0.5f);BitmapFactory.Options options = new BitmapFactory.Options();//设置图片的采样率options.inSampleSize = scaleSize;//针对不同的手机分辨率,设置的缩放比也不一样,这里的值可能是不一样的Bitmap bitmap = BitmapFactory.decodeFile(path, options);return bitmap;}}

运行结果:


这篇关于浅谈android中加载高清大图及图片压缩方式(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1111971

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

浅谈主机加固,六种有效的主机加固方法

在数字化时代,数据的价值不言而喻,但随之而来的安全威胁也日益严峻。从勒索病毒到内部泄露,企业的数据安全面临着前所未有的挑战。为了应对这些挑战,一种全新的主机加固解决方案应运而生。 MCK主机加固解决方案,采用先进的安全容器中间件技术,构建起一套内核级的纵深立体防护体系。这一体系突破了传统安全防护的局限,即使在管理员权限被恶意利用的情况下,也能确保服务器的安全稳定运行。 普适主机加固措施:

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

用命令行的方式启动.netcore webapi

用命令行的方式启动.netcore web项目 进入指定的项目文件夹,比如我发布后的代码放在下面文件夹中 在此地址栏中输入“cmd”,打开命令提示符,进入到发布代码目录 命令行启动.netcore项目的命令为:  dotnet 项目启动文件.dll --urls="http://*:对外端口" --ip="本机ip" --port=项目内部端口 例: dotnet Imagine.M

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存