2011-01-08 27 views
8

我需要在創建圖像之前縮放圖像,並且只有在超過1024KB(例如)時才需要。如何在創建位圖之前從InputStream獲知位圖大小?

通過執行以下操作,我可以縮放圖像,但我只需要規模是大於給定尺寸更大的人。

Bitmap bmImg = null; 
InputStream is = url.openStream(); 
BitmapFactory.Options opts = new BitmapFactory.Options(); 
opts.inSampleSize = 10; 
bmImg = BitmapFactory.decodeStream(is,null,opts); 

我怎樣才能得到位圖的大小? (我很高興知道字節數量,而不是解壓縮後的大小)。

編輯:

我想這一點:

BitmapFactory.Options opts = new BitmapFactory.Options(); 
opts.inJustDecodeBounds = true; 
Bitmap bmImg=BitmapFactory.decodeStream(is,null,opts); 
Log.e("optwidth",opts.outWidth+""); 
Bitmap bmImg1 = BitmapFactory.decodeStream(is); 

我第一次使用的InputStream(是),將其與「inJustDecodeBounds」解碼工作正常,我可以得到位圖尺寸。 問題是,我第二次使用它來實際解碼圖像,沒有圖像顯示。

我在做什麼錯?

回答

0

無法通過其本身的定義,從流中獲取大小。如果你願意,你可以將流加載到一個字節數組中,從中獲取字節數。你也可以使用BitmapFactory直接解碼一個字節數組,這樣可以很好地解決問題。

InputStream in = ... 
ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
int i; 
while ((i = in.read()) != -1) { 
    bos.write(i); 
} 
byte[] byteArray = bos.toByteArray(); 
if (byteArray.length > SOME_VALUE) { 
    // do things here 
} 
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length); 
+0

這實際上有效,但它的方式更慢。 – sergi 2011-01-09 00:27:31

-2

你不能得到一個位圖的大小,那裏只是沒有一個內置的方式。但是,您可以獲取內容(文件)的大小,這是您可能需要執行的操作。像這樣的東西應該工作。

int file_size = url.getContentLength(); 
+0

url是哪一種?我在java.net.URL中找不到這個方法 – Vikas 2011-01-12 09:23:25

+0

這個用戶實際上是指URLConnection [見這裏](http://developer.android.com/reference/java/net/URLConnection.html)。但是這種方法確實不被推薦..它依賴於服務器提供一個有效的Content-Length頭(如果數據被壓縮,這個頭可能會引起誤解)。 – kwazi 2012-09-17 16:05:11

2

如果您知道文件的格式,您可能會讀取該文件的標題。習慣上,標題包含圖像的大小和格式。幸運的是,這總是文件的第一個字節。

對於某些類型的也許是不可能的。

PNGJPEGBMPTGA

剛剛看了一下標題,你可能必須先猜寬度的一些文件。例如,PNG似乎沒有包含widht/height,但是您應該能夠讀取寬度並根據像素大小/比率猜測高度。

編輯:我的壞我以爲你想要使用的尺寸縮放...是啊ContentLenght應該幫助,但有時它會返回0,如果服務器沒有設置在HTTP報頭右側尺寸。在這種情況下,你需要知道返回的大小。但無論如何,你可以保存一個bytearray,一旦加載完畢,只需檢查數組的長度。如果它大於1024kb,則調整圖像大小。並保存它或做任何你想要的東西。當你從他們讀

0

大多數流消耗。在你的第二個代碼塊中,你第一次使用流作爲位圖。當你第二次調用decodeString的時候,流是'空的'(如果只是在所有數據已經​​被讀取的情況下)。

最好的答案可能會被monkjack的,但也許只是一點點額外的代碼,以確保你不讀一個龐大的文件到內存中。我建議您在將數據流傳輸到緩衝區時檢查大小(即停止在10MB);我不確定Android會如何處理內存不足異常。

+0

問題是monkjack的解決方案要慢得多。 當我嘗試分配太大的圖像時,Android剛剛崩潰。 – sergi 2011-01-08 22:56:40

2

您可以將is換成new BufferedInputStream(is);,然後使用mark(int readlimit)reset()方法重新讀取數據流。您需要決定設置readlimit以允許它讀取整個標題,Loïc提供的鏈接應該在這裏提供幫助。

BufferedInputStream bis = new BufferedInputStream(is); 
bis.mark(1024 * 1024); 
BitmapFactory.Options opts = new BitmapFactory.Options(); 
opts.inJustDecodeBounds = true; 
Bitmap bmImg=BitmapFactory.decodeStream(bis,null,opts); 
Log.e("optwidth",opts.outWidth+""); 
bis.reset(); 
Bitmap bmImg1 = BitmapFactory.decodeStream(bis); 

我已經離開了相應的錯誤處理的reset()方法,如果你讀過從流超過readlimit字節就會拋出IOException

+0

我正在嘗試這個,我得到了一些隨機圖像: java.io.IOException:馬克已經失效 我得到它在75KB,120KB的圖像,而不是在45KB或700KB的圖像.. – sergi 2011-06-18 12:49:44

5

我是一個noob,所以我不能直接評論monkjack的答案。他的回答太慢的原因是它一次只複製一個字節。使用1K的緩衝區將顯着提高性能。

InputStream in = getContentResolver().openInputStream(docUri); 

ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
int i; 
byte[] buffer = new byte[1024]; 
while ((i = in.read(buffer)) != -1) { 
    bos.write(buffer); 
} 
byte[] docbuffer = bos.toByteArray(); 
0

如果您正在縮減,以防止OutOfMemoryException我一樣,該解決方案可以更好地爲您(在這裏提供的答案建築):

// <initialize stream> 

// figure out number of bytes in stream 
byte[] bytes = new byte[1024]; 
int i; 
int byteCount = 0; 
while ((i = stream.read(bytes)) != -1) { 
    byteCount += i; 
} 

// <reset stream> 

Bitmap bmImg; 

// downsample if necessary 
if (byteCount > MAX_SIZE) { 
    // scale down photo if too large 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    // scale to nearest power of 2 - faster 
    options.inSampleSize = (int)Math.pow(2, (int)(Math.log10(Math.sqrt((double)byteCount/MAX_SIZE))/Math.log10(2) + 1)); // 2^(log2(lengthRatio)+1) 
    options.inPreferredConfig = Bitmap.Config.ARGB_8888; 
    bmImg = BitmapFactory.decodeStream(stream, null, options); 
} 
else { 
    bmImg = BitmapFactory.decodeStream(stream); 
} 

我避免使用mark(int)reset()因爲在我情況下,流的大小沒有上限。所以如何重置流可能取決於你的實現。我流是由Uri指定的,所以我只是用:

stream.close(); 
stream = this.getContentResolver().openInputStream(uri); // where this is an Activity 

重置流。

2

如果your're試圖防止內存溢出或其他什麼東西......

您可以創建您的圖片數據的緩衝器,

BitmapFactory.Options buffer = new BitmapFactory.Options(); 
buffer.inJustDecodeBounds = true; 
BitmapFactory.decodeByteArray(photo, 0, photo.length, buffer); 

然後你可以使用buffer.outHeight大小, buffer.outWidth ..

如果你想縮放,你只是使用buffer.isSampleSize,但我注意到你設置了一個「10」值......我認爲是錯誤的... sampleSize應該得到一個2 ^值..如2,4,8,16等

最後在sampleSize設置後,您可以像往常一樣創建位圖。

Bitmap bmp = BitmapFactory.decodeByteArray(photo, 0, photo.length, buffer); 

希望能幫到你!

PS:SQS我的英語=(!

0

檢查logcat的,如果你有說"Bitmap too large to be uploaded into a texture"那麼你需要做到以下幾點我的答案是類似@Sergio A.但你可以用一個錯誤。直接BitmapFactory.decodeStream代替decodeByteArray。

final BitmapFactory.options = new BitmapFactory.Options(); 
options.inJustDecodeBounds = true; 

// Pass in a Rect if you want to know the padding. 
BitmapFactory.decodeStream(inputStream,null,options); 

這將讓圖像(不是整個圖像本身)的只是大小。您可以使用下面的代碼分離的寬度和高度。

final int height = options.outHeight; 
final int width = options.outWidth; 

您可以使用這些值(連同所需的寬度和高度 - 最有可能的基礎上的ImageView或屏幕)來計算options.inSampleSize。我不打算怎麼做,但Google提供了一個教程here

希望幫助:)

相關問題