2011-01-08 32 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

希望帮助:)

相关问题