日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android 图片缩放算法,Android大图加载,缩放,滑动浏览--SubsamplingScaleImageView 源码分析大图加载...

發布時間:2025/3/21 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 图片缩放算法,Android大图加载,缩放,滑动浏览--SubsamplingScaleImageView 源码分析大图加载... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

**************這個開源項目有點大的,也不知道幾篇能寫完,先根據功能點分析解讀*********************

1.寫在前面

圖片瀏覽的坑不少,大圖加載導致內存溢出的情況相信每個人都遇到過,最早的解決辦法是利用?BitmapFactory.Options自己解決,簡單的實現方式:public Bitmap decodeBitMapFromFileDescriptor(FileDescriptor fd,int reqWidth,int reqHeight){

BitmapFactory.Options options = new BitmapFactory.Options();

//解析目標圖片寬高

options.inJustDecodeBounds = true;

BitmapFactory.decodeFileDescriptor(fd,null,options);

options.inSampleSize = calculateInSimpleSize(options, reqWidth, reqHeight);

options.inJustDecodeBounds = false;

return BitmapFactory.decodeFileDescriptor(fd,null,options);

}

/**

* 計算采樣率

* @param options

* @param reqWidth

* @param reqHeight

*/

private int calculateInSimpleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

//初始采樣率

int inSimpleSize = 1;

//判0

if(reqWidth==0||reqHeight==0){

return 1;

}

//獲取圖片解析寬高

final int width = options.outWidth;

final int height = options.outHeight;

LogUtil.LogE("原始圖片寬高,width:"+width+",heght:"+height);

if(height>reqHeight||width>reqWidth){

//任意寬高大于需求寬高

final int halfHeight = height/2;

final int halfWidth = width/2;

//定義循環 不斷縮小halfheight 直到任意小于目標寬高跳出循環

while((halfHeight/inSimpleSize)>=reqHeight&&(halfWidth/inSimpleSize)>=reqWidth){

//官方建議取值為2的指數冪

inSimpleSize*=2;

}

}

return inSimpleSize;

}

這是根據《安卓開發藝術探索》 圖片加載一章實現的圖片緩存工具,這個類就是用來等比例縮小圖片質量,從而減小bitmap占用內存,防止內存溢出。

但是實際需求中,當你一個頁面顯示大圖瀏覽時,不可能是只顯示圖片就完了的,雙擊縮放,放大時滑動瀏覽,這些基本功能肯定要有,最早實現這些功能,是看了鴻洋大神的文章,模仿寫的,博客地址:點擊打開鏈接?,勉強能用,后來發現了這個開源項目 github:https://github.com/davemorrissey/subsampling-scale-image-view,基本上你能想到的功能他都有了。下面我會根據幾個功能點來解讀源碼。

二、源碼分析

首先看功能,第一個肯定是最基本的大圖加載,先說下使用方式:public class MainActivity extends Activity { private SubsamplingScaleImageView mSubsamplingScaleImageView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSubsamplingScaleImageView=(SubsamplingScaleImageView) findViewById(R.id.subsamplingScaleImageView); mSubsamplingScaleImageView.setImage(ImageSource.asset("china.jpg")); } }

ImageSource 類 指定圖片加載途徑,1、直接加載Bitmap ,2.、圖片緩存路徑加載、3.資源id加載、4.asset 資源文件加載(超大圖片必備);與此同時他還初始化了一些bitmap的特性值,最重要的就是

region這是一個

Rect指定了顯示大圖某一個區域,詳細的介紹后面會說。先來看setImage以后做了什么if (imageSource.getBitmap() != null && imageSource.getSRegion() != null) {

//從bitmap加載 指定顯示區域

onImageLoaded(Bitmap.createBitmap(imageSource.getBitmap(), imageSource.getSRegion().left, imageSource.getSRegion().top, imageSource.getSRegion().width(), imageSource.getSRegion().height()), ORIENTATION_0, false);

} else if (imageSource.getBitmap() != null) {

//從bitmap加載 沒有指定顯示區域

onImageLoaded(imageSource.getBitmap(), ORIENTATION_0, imageSource.isCached());

} else {

// imageSource.getBitmap() ==null 從resource asset 加載圖片

sRegion = imageSource.getSRegion();

uri = imageSource.getUri();

if (uri == null && imageSource.getResource() != null) {

// 圖片源是資源id

uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getContext().getPackageName() + "/" + imageSource.getResource());

}

if (imageSource.getTile() || sRegion != null) {

// Load the bitmap using tile decoding.

// 展開

TilesInitTask task = new TilesInitTask(this, getContext(), regionDecoderFactory, uri);

execute(task);

} else {

// Load the bitmap as a single image.

BitmapLoadTask task = new BitmapLoadTask(this, getContext(), bitmapDecoderFactory, uri, false);

execute(task);

}

}

這里對圖片源做了一系列判斷,是否有Bitmap 對象,是否指定區域顯示,關于圖片的區域顯示,也可先看看鴻洋大神的這篇文章:http://blog.csdn.net/lmj623565791/article/details/49300989

這里首先進入TilesInitTask 進行展開初始化任務,獲取圖片寬高和方向信息,進行第一次繪制,從onDraw中進入initialiseBaseLayer方法

這個Task的主要目的就是判斷需要繪制的bitmap寬高有沒有超出Canvas的最大繪制寬高,防止報錯;如果沒有超出,就從BitmapLoadTask進行正常加載圖片。

核心類就是?BitmapRegionDecoder前面說的region就是通過它來顯示指定一個矩形區域; 進入BitmapLoadTask ,AsyncTask子類,核心處理在doInbackgroudtry {

String sourceUri = source.toString();

Context context = contextRef.get();

//根據實現類不同 decoderFactory的解析方式不同 縮放模式顯示指定區域時,

// 實現類factory初始化了BitmapRegionDecoder 對象,從而指定region 解析出bitmap (可以自己看下SkiaImageRegionDecoder這個類源碼)

//這里factory實現類 通過BitmapFactory來解析bitmap

DecoderFactory extends ImageDecoder> decoderFactory = decoderFactoryRef.get();

SubsamplingScaleImageView view = viewRef.get();

if (context != null && decoderFactory != null && view != null) {

view.debug("BitmapLoadTask.doInBackground");

// 沒有指定顯示區域時解析獲取bitmap對象

bitmap = decoderFactory.make().decode(context, source);

//返回值是圖片方向

return view.getExifOrientation(context, sourceUri);

}

} ...錯誤處理

同樣的對BitmapRegionDecoder解析的bitmap對象進行全尺寸的圖片加載 在加載方法中對當前圖片的屬性值進行初始化,寬高,方向等,然后再次進入onDraw方法,在fitBounds方法中計算圖片scale以及采樣率。

最后進行圖片的繪制else if (bitmap != null) {

float xScale = scale, yScale = scale;

if (matrix == null) { matrix = new Matrix(); }

matrix.reset();

matrix.postScale(xScale, yScale);

matrix.postRotate(getRequiredRotation());

matrix.postTranslate(vTranslate.x, vTranslate.y);

if (getRequiredRotation() == ORIENTATION_180) {

matrix.postTranslate(scale * sWidth, scale * sHeight);

} else if (getRequiredRotation() == ORIENTATION_90) {

matrix.postTranslate(scale * sHeight, 0);

} else if (getRequiredRotation() == ORIENTATION_270) {

matrix.postTranslate(0, scale * sWidth);

}

if (tileBgPaint != null) {

if (sRect == null) { sRect = new RectF(); }

sRect.set(0f, 0f, bitmapIsPreview ? bitmap.getWidth() : sWidth, bitmapIsPreview ? bitmap.getHeight() : sHeight);

matrix.mapRect(sRect);

canvas.drawRect(sRect, tileBgPaint);

}

canvas.drawBitmap(bitmap, matrix, bitmapPaint);

}

這里需要知道是的Matrix,這是一個三維矩陣,內部存儲了一個長度為9 的數組{

MSCALE_X, MSKEW_X, MTRANS_X,

MSKEW_Y, MSCALE_Y, MTRANS_Y,

MPERSP_0, MPERSP_1, MPERSP_2

};

這幾個值控制了圖像的位移,縮放,旋轉,具體使用時有直接方法,可以去看Api

到這里就完成一次完成大圖的縮放加載。與之前的方法不同的是,這樣加載后并沒有損失圖像質量,便于放大后查看,文章開始的方法使用采樣率加載通過損失圖像質量來降低內存小號,這里則是縮放圖像來降低內存。

————————————————————–

這么寫下來沒個幾篇是寫不完了,這篇就到這,下一篇會分析雙擊屏幕后的處理。

總結

以上是生活随笔為你收集整理的android 图片缩放算法,Android大图加载,缩放,滑动浏览--SubsamplingScaleImageView 源码分析大图加载...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。