偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

如何為你的Android應(yīng)用縮放圖片

移動(dòng)開發(fā) Android
如何為你的Android應(yīng)用縮放圖片?我們所提供的解決方案,將有一個(gè)結(jié)構(gòu)類似上述代碼,其中的一部分將取代行1,這樣為縮放做準(zhǔn)備。另一部分將取代行2,做最后的縮放。我們將開始替換行2的部分代碼,引入兩個(gè)新的概念,裁剪和合適。

很難為你的應(yīng)用程序得到正確的圖像縮放嗎?是你的圖片過大,造成內(nèi)存問題?還是圖片不正確縮放造成不良用戶體驗(yàn)的結(jié)果?為了尋求一個(gè)好的解決方案,我們咨詢了Andreas Agvard(索尼愛立信軟件部門),讓他分享一些關(guān)于這方面的經(jīng)驗(yàn)。

[[73551]]

在索尼愛立信軟件部門工作,我經(jīng)常遇到需要圖片縮放的應(yīng)用,例如:當(dāng)處理別人或者網(wǎng)絡(luò)上提供的圖片??s放是必要的,因?yàn)橥ǔG闆r下的圖片不是你想要呈現(xiàn)的那樣。

典型的例子,如果你正在為你的應(yīng)用開發(fā)一個(gè)LiveView™擴(kuò)展。大多數(shù)人開發(fā)應(yīng)用利用LiveView™和其他第二屏幕設(shè)備,可能需要重新調(diào)整圖片,重要的是要保持適當(dāng)?shù)目s放比例和圖像質(zhì)量。當(dāng)然,在很多情況下,改變圖片尺寸是一個(gè)有點(diǎn)困難,但是很有效的途徑。

ImageView解決了許多的圖片縮放問題,首先,至少你在設(shè)置完一個(gè)圖片源后,不用去解碼或縮放圖片。但有時(shí)需要你自己去解碼控制,這是本教程的用武之地。隨著本教程,我寫了一個(gè)代碼示例,下載圖片縮放代碼示例。在文本中呈現(xiàn)的效果,可以通過編譯和運(yùn)行該項(xiàng)目來看到。

孤立的問題

我做這個(gè)教程,是因?yàn)槲乙呀?jīng)有一些實(shí)用方法來實(shí)現(xiàn)圖片的縮放,為了避免最常見的圖片縮放問題。如下面的例子:

  1. Bitmap unscaledBitmap = BitmapFactory.decodeResource(getResources(), mSourceId); 
  2. Bitmap scaledBitmap = Bitmap.createScaledBitmap(unscaledBitmap, wantedWidth, wantedHeight, true); 

那么在上面的代碼中,什么是正確的,什么是錯(cuò)的?讓我們來看看在不同的代碼行。

行1:整個(gè)源圖像解碼到一個(gè)位圖。

  • 這可能會(huì)導(dǎo)致內(nèi)存不足的錯(cuò)誤,如果圖片太大的話。
  • 這可能會(huì)導(dǎo)致在一個(gè)高分辨率上解碼圖像。這可能會(huì)很慢,但智能解碼器可為解碼提高性能。
  • 縮放圖片很多時(shí)候是,高分辨率位圖縮放到低分辨率,會(huì)導(dǎo)致鋸齒的問題。使用位圖過濾(例如,通過傳送`true`參數(shù)到Bitmap.createScaledBitmap(...))減少了鋸齒,但是還是不夠。

行2:解碼的位圖縮放到想要的大小。

  • 源圖像的尺寸和想要的圖像尺寸在長寬比上可能是不一樣的。這將導(dǎo)致圖像的拉伸。

左邊的圖片:原始圖像。右邊的圖片:縮放后圖片??梢钥闯雒黠@的失真問題,如原圖的眼睛非常的鮮明,縮放后就沒有了。高度出現(xiàn)拉伸。

創(chuàng)建一個(gè)解決方案

我們的解決方案,將有一個(gè)結(jié)構(gòu)類似上述代碼,其中的一部分將取代行1,這樣為縮放做準(zhǔn)備。另一部分將取代行2,做最后的縮放。我們將開始替換行2的部分代碼,引入兩個(gè)新的概念,裁剪和合適。

替換行2

在這一部分,我們將縮放位圖到我們所需要的。這一步很必要,因?yàn)橹暗慕獯a能力是有限的。此外,在這一步為了避免拉伸,我們可能要重新調(diào)整圖片到想要的大小。

有兩種可能性可以避免拉伸。不管是那種,我們都要調(diào)整尺寸,以確保他們有相同的寬高比;即縮放圖像作為源圖像,直到它適合想要的尺寸,或裁剪具有相同的寬高比的源圖像為想要的尺寸。

左邊的圖片:圖像通過fit方法縮放。圖片已被縮小到適合的尺寸和高度,結(jié)果是小于想要的高度。右邊的圖像:圖像crop方法縮放。圖像已被縮放到適應(yīng)至少想要的尺寸。因此原圖已被裁剪,切割了成左邊和右邊二部分。

為了縮放這樣的效果,我們的實(shí)現(xiàn)代碼如下:

  1. public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int dstWidth, int dstHeight, ScalingLogic scalingLogic) { 
  2.       Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic); 
  3.       Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(), dstWidth, dstHeight, scalingLogic); 
  4.       Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(), Config.ARGB_8888); 
  5.       Canvas canvas = new Canvas(scaledBitmap); 
  6.       canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));return scaledBitmap; 
  7.       } 

在上面的代碼,我們使用canvas.drawBitmap(...)做縮放。這種方法的裁剪區(qū)域是從源圖像的規(guī)模面積定義畫布的矩形為指定的目標(biāo)矩形區(qū) 域。為了避免拉伸,這兩個(gè)矩形需要有相同的長寬比。我們還調(diào)用了兩個(gè)實(shí)用的方法,一個(gè)為創(chuàng)建源矩形和另一個(gè)為創(chuàng)建目標(biāo)矩形。方法如下:

  1. public static Rect calculateSrcRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight, ScalingLogic scalingLogic) { 
  2.       if (scalingLogic == ScalingLogic.CROP) { 
  3.         final float srcAspect = (float)srcWidth / (float)srcHeight; 
  4.         final float dstAspect = (float)dstWidth / (float)dstHeight; 
  5.         if (srcAspect > dstAspect) { 
  6.           final int srcRectWidth = (int)(srcHeight * dstAspect); 
  7.           final int srcRectLeft = (srcWidth - srcRectWidth) / 2
  8.           return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight); 
  9.         } else { 
  10.           final int srcRectHeight = (int)(srcWidth / dstAspect); 
  11.           final int scrRectTop = (int)(srcHeight - srcRectHeight) / 2
  12.           return new Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight); 
  13.         } 
  14.       } else { 
  15.         return new Rect(00, srcWidth, srcHeight); 
  16.       } 
  17.     } 
  18.     public static Rect calculateDstRect(int srcWidth, int srcHeight, int dstWidth, int dstHeight, ScalingLogic scalingLogic) { 
  19.       if (scalingLogic == ScalingLogic.FIT) { 
  20.         final float srcAspect = (float)srcWidth / (float)srcHeight; 
  21.         final float dstAspect = (float)dstWidth / (float)dstHeight; 
  22.         if (srcAspect > dstAspect) { 
  23.           return new Rect(00, dstWidth, (int)(dstWidth / srcAspect)); 
  24.         } else { 
  25.           return new Rect(00, (int)(dstHeight * srcAspect), dstHeight); 
  26.         } 
  27.       } else { 
  28.         return new Rect(00, dstWidth, dstHeight); 
  29.       } 
  30.     } 

在剛好合適的情況下源矩形會(huì)包含整個(gè)源尺寸。在需要裁剪的情況下,它會(huì)計(jì)算好具有相同寬高比的目標(biāo)圖像,來裁剪源圖像的寬度或高度,以達(dá)到你想要的尺寸。而剛好在合適的情況下,將有相同寬高比的源圖像,調(diào)整成你想要的尺寸的寬度或高度。

替換行1

解碼器很智能,特別是用于JPEG和PNG的格式。這些解碼器在圖片解碼時(shí)可以進(jìn)行縮放,并且性能也有所改善,這樣鋸齒問題也可以避免。此外,由于圖片解碼后變小了,需要的內(nèi)存也會(huì)較少。

縮放解碼的時(shí)候,只要簡單設(shè)置上BitmapFactory.Options對象的inSampleSize參數(shù),并把它傳遞給 BitmapFactory。樣本大小指定一個(gè)縮放圖像大小的抽象因素,例如2是640×480圖像在320×240圖像上解碼的因素。樣本大小設(shè)置時(shí), 你不能保證嚴(yán)格按照這個(gè)數(shù)字,圖像將被縮減,但至少它不會(huì)更小。例如,3倍640×480的圖像可能會(huì)導(dǎo)致在一個(gè)320×240圖像不支持值。通常情況 下,至少2的一次方支持[1,2,4,8,...]。

下一步是指定一個(gè)合適的樣本大小。合適的樣本大小將產(chǎn)生最大的縮放,但仍然是大于等于你想要的圖像尺寸。如下面代碼:

  1. public static Bitmap decodeFile(String pathName, int dstWidth, int dstHeight, ScalingLogic scalingLogic) { 
  2.       Options options = new Options(); 
  3.       options.inJustDecodeBounds = true
  4.       BitmapFactory.decodeFile(pathName, options); 
  5.       options.inJustDecodeBounds = false
  6.       options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, dstWidth, dstHeight, scalingLogic); 
  7.       Bitmap unscaledBitmap = BitmapFactory.decodeFile(pathName, options); 
  8.       return unscaledBitmap; 
  9.     } 
  10.     public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight, ScalingLogic scalingLogic) { 
  11.       if (scalingLogic == ScalingLogic.FIT) { 
  12.         final float srcAspect = (float)srcWidth / (float)srcHeight; 
  13.         final float dstAspect = (float)dstWidth / (float)dstHeight; 
  14.         if (srcAspect > dstAspect) { 
  15.           return srcWidth / dstWidth; 
  16.         } else { 
  17.           return srcHeight / dstHeight; 
  18.         } 
  19.       } else { 
  20.         final float srcAspect = (float)srcWidth / (float)srcHeight; 
  21.         final float dstAspect = (float)dstWidth / (float)dstHeight; 
  22.         if (srcAspect > dstAspect) { 
  23.           return srcHeight / dstHeight; 
  24.         } else { 
  25.           return srcWidth / dstWidth; 
  26.         } 
  27.       } 
  28.     } 

在decodeFile(...)方法中,我們解碼一個(gè)文件進(jìn)行了最終縮放尺度。這是首先要通過解碼源圖片尺寸,然后使用 calculateSampleSize(...)計(jì)算最佳樣本大小,最后使用此樣本的大小解碼圖像。如果你有興趣的話,你可以更深入了解 calculateSampleSize(...)方法,但以上方法基本可確保圖片進(jìn)行縮放。

全部放在一起

根據(jù)上面我們指定的方法的,現(xiàn)在可以執(zhí)行替換最初的代碼行:

  1. Bitmap unscaledBitmap = decodeFile(pathname, dstWidth, dstHeight, scalingLogic); 
  2. Bitmap scaledBitmap = createScaledBitmap(unscaledBitmap, dstWidth, dstHeight, scalingLogic);

左邊的圖像:原始解決方案,解碼消耗6693 KB的內(nèi)存和1/4秒左右。結(jié)果被拉長失真。中間的圖像:同比縮放解決方案,解碼消耗418 KB的內(nèi)存和1/10秒左右。右邊的圖像:裁剪解決方案,解碼消耗418 KB的內(nèi)存和1/10秒左右。

想要了解更多信息,請下載我們的代碼示例。有了這個(gè)源碼項(xiàng)目,你可以看到你的Android手機(jī)上運(yùn)行的結(jié)果。

責(zé)任編輯:閆佳明 來源: open-open
相關(guān)推薦

2013-08-06 13:50:09

2011-02-22 14:42:52

AndroidPad

2021-06-29 09:00:00

機(jī)器人ITRPA

2024-09-30 08:01:44

2021-06-30 09:11:17

KubernetesDevtronK8S

2012-12-31 13:13:13

App出售

2020-04-24 06:26:09

LinuxPython應(yīng)用

2021-07-14 13:30:44

KubernetesLinux文件

2012-04-25 22:56:10

Android

2016-12-26 10:28:00

2023-12-26 10:04:29

Electron應(yīng)用開發(fā)框架

2015-03-31 10:26:01

數(shù)據(jù)庫數(shù)據(jù)庫事務(wù)

2015-06-08 10:07:04

公有云云服務(wù)商選擇公有云遷移

2020-03-30 17:43:13

開源開源項(xiàng)目編寫文檔

2010-12-14 13:40:33

IPv4IPv6Windows 7

2022-12-26 10:28:08

CIO技術(shù)領(lǐng)導(dǎo)者

2020-12-31 09:39:39

應(yīng)用圖像格式SVGOMG

2012-02-07 09:31:59

2011-11-09 10:50:52

2015-08-31 09:38:33

Linux安裝
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號