How to find out the size of a bitmap from an InputStream before creating a bitmap?

I need to scale the image before creating it, and I want to do this only if it exceeds 1024 KB (for example).

By doing the following, I can scale the image, but I need to scale only those that are larger than the specified size.

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

How can I get the size of the bitmap? (I'm glad I know the number of bytes, not the size after decompression).

Edit:

I am trying to do this:

 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); 

The first time I use InputStream (is) to decode it with "inJustDecodeBounds", it works fine and I can get the bitmap sizes. The problem is that the second time I use it to actually decode the image, the image is not displayed.

What am I doing wrong?

+8
android
source share
9 answers

I am noob, so I can not directly comment on monkjack's answer. The reason his answer is so slow is because he copies one byte at a time. Using a buffer of even 1K will significantly improve performance.

 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(); 
+5
source share

If you know the file format, you can read the file header. Typically, the header contains the size and format of the image. And fortunately for you, these are always the first bytes of a file.

This may not be possible for certain types.

PNG , JPEG , BMP , TGA

Just read about the header and some file that might need to guess the width first. For example, PNG does not seem to include widht / height, but you should be able to read the width and guess the height with the pixel size / ratio.

Edit: bad I thought you wanted to scale using the dimension ... Yes ContentLenght should help, but sometimes it returns 0 if the server does not set the correct dimension in the http header. In this case, you need to know the return size. But in any case, you can save bytearray, and as soon as everything is loaded, just check the length of the array. if it is larger than 1024 KB, resize the image. And save it or do whatever you want.

+2
source share

You can wrap is with new BufferedInputStream(is); and use the mark(int readlimit) and reset() methods to read the stream again. You will need to decide what to install readlimit so that it can read the entire header, the links provided by LoΓ―c should help here.

 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); 

I missed the appropriate error handling for the reset() method, it will throw an IOException if you read more than readlimit bytes from the stream.

+2
source share

If you are trying to prevent OutOfMemory or something else ...

you can create a buffer with your image data,

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

Then you can get the size using buffer.outHeight, buffer.outWidth ..

If you want to scale, you just use buffer.isSampleSize, but I noticed that you set the value to "10" there ... which I think is wrong ... sampleSize should get the value 2 ^ .. as 2, 4, 8, 16 etc.

Finally, after installing sampleSize, you can create a bitmap as always.

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

hope to help you!

PS: SQS MY ENGLISH = (!!!

+2
source share

You cannot get size from a stream by its very definition. If you want, you can load the stream into an array of bytes, get the number of bytes from it. You can also use BitmapFactory to directly decode an array of bytes, so that would be very good.

 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
source share

Most threads are consumed when you read them. In the second block of code, you consume the stream for the first time as a bitmap. When you call decodeString a second time, the stream is "empty" (if only in the sense that all the data has already been read).

Monkjack will probably be the best answer, but perhaps with a little extra code so you don't read the giant file into memory. I recommend only checking when you pass it to the buffer for size (i.e. stop at 10 MB); I'm not sure how well Android will handle an exception in memory.

0
source share

If you zoom out to prevent an OutOfMemoryException like me, this solution may work better for you (based on the answers presented here):

 // <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); } 

I avoided using mark(int) and reset() , because in my case there is no upper limit on the size of the stream. So how to reset the thread may depend on your implementation. My stream was specified by Uri , so I just used:

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

to reset the stream.

0
source share

Check logcat if you have a bug that says "Bitmap too large to be uploaded into a texture" , then you need to do the following. My answer is similar to @Sergio A., but you can use BitmapFactory.decodeStream directly instead of 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); 

This will only get the size of the image (not the whole image). You can highlight the width and height using the following code.

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

You can use these values ​​(along with your desired width and height - most likely based on an imageView or screen) to calculate options.inSampleSize . I am not going to do this, but Google has provided a tutorial here .

Hope that helps :)

0
source share

You cannot get the size of the bitmap, there is simply no built-in way. However, you can get the size of the content (file) that you probably need. Something like this should work.

 int file_size = url.getContentLength(); 
-2
source share

Source: https://habr.com/ru/post/650835/


All Articles