Getting the size of an image inputstream
Asked Answered
O

1

5

I need to get the height and width of the image found in the inputstream. Here is what I did:

private Boolean testSize(InputStream inputStream){
        BitmapFactory.Options Bitmp_Options = new BitmapFactory.Options();
        Bitmp_Options.inJustDecodeBounds = true;
        BitmapFactory.decodeResourceStream(getResources(), new TypedValue(), inputStream, new Rect(), Bitmp_Options);
        int currentImageHeight = Bitmp_Options.outHeight;
        int currentImageWidth = Bitmp_Options.outWidth;
        Bitmp_Options.inJustDecodeBounds = false;
    if(currentImageHeight < 200 || currentImageWidth < 200){
        Object obj = map.remove(pageCounter);
        Log.i("Page recycled", obj.toString());
        return true;
    }
    return false;}

Skipping to the problem at point:

It change BitmapFactory.Options even if I forced it to be false after calculation on my second method below.

private Bitmap getBitmap(InputStream InpStream){
    Bitmap originalBitmap = BitmapFactory.decodeStream(InpStream);//Null.
    return originalBitmap;
}

Now to my question is there another way of getting the size and width of an image from an inputstream? I really need help on this any help is greatly appreciated.

                ZipInputStream zip = null;
                zip = new ZipInputStream(new FileInputStream(getFileLocation()));
                for(ZipEntry zip_e = zip.getNextEntry(); zip_e != null ; zip_e = zip.getNextEntry()){
                    if(zip_e.isDirectory()) {
                        continue;
                    }
                    String file_zip = zip_e.getName();
                    String comparison = map.get(pageCounter).getHref();
                    if(file_zip.endsWith(comparison)){
                        SpannableString Spanable_String = new SpannableString("abc");
                        if(testSize(zip)){
                            map.remove(pageCounter);
                            return false;
                        }
                        Bitmap bitmap = getBitmap(zip);
                        if(bitmap == null){
                            map.remove(pageCounter);
                            return false;
                        }
                        image_page.put(zip_e.getName(), zip);
                        Drawable drawable_image = new FastBitmapDrawable(bitmap);
                        drawable_image.setBounds(0,0,drawable_image.getIntrinsicWidth(), drawable_image.getIntrinsicHeight());
                        ImageSpan imageSpan = new ImageSpan(drawable_image, ImageSpan.ALIGN_BASELINE);
                        Spanable_String.setSpan(imageSpan, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        tv.setText(Spanable_String);
                        return false;
                    }
                }   
Overwind answered 26/6, 2012 at 18:25 Comment(5)
Are you saying that the setting Bitmp_Options.inJustDecodeBounds to true is being persisted for subsequent calls to BitmapFactory.decodeStream()?Unvalued
Yes, I am saying it's true. For some reason without testSize method it will work properly same inputstream and same source. I find it a very strange behaviour that I had to report it as a bug.Overwind
Yes, I'd say that would certainly not be the expected behavior. I'm not sure that there is another (good) way to get the image size from an input stream.Unvalued
Can you post the code that calls these functions?Rushy
I will do it but for confidential reason for my company I can't reveal most of it.Overwind
J
11

The main problem is not with the BitmapFactory.Options, but with the InputStream. The stream is sequential, therefore when you read the stream to decode the image for size only, the pointer in the stream is moving. Next, when you're calling decode again to actually decode the bitmap, the stream pointer is no longer at the beginning of the bitmap, and you get null because the partial stream cannot be decode.

You would need to reset the stream. Depending on what that stream is, you might be able to use .mark and .reset on it. Essentially, you'd do something like this:

private Boolean testSize(InputStream inputStream) {
    BitmapFactory.Options Bitmp_Options = new BitmapFactory.Options();
    Bitmp_Options.inJustDecodeBounds = true;

    inputStream.mark(inputSteram.available());

    BitmapFactory.decodeResourceStream(getResources(), new TypedValue(), inputStream, new Rect(), Bitmp_Options);

    inputSteram.reset();

    int currentImageHeight = Bitmp_Options.outHeight;
    int currentImageWidth = Bitmp_Options.outWidth;
    Bitmp_Options.inJustDecodeBounds = false;

    if(currentImageHeight < 200 || currentImageWidth < 200){
        Object obj = map.remove(pageCounter);
        Log.i("Page recycled", obj.toString());
        return true;
    }

    return false;
}

You can check whether your InputStream supports this or not by calling markSupported on it. If that returns true then you can use the above technique. If it returns false, then the above method will not work and you will actually need to close and reopen the stream again before decoding the full bitmap.

Jodee answered 26/6, 2012 at 19:16 Comment(4)
Thank you. You saved me many hours of trying to figure this out. Thank you again for telling me it is sequential.Overwind
Ah, didn't realize you were calling this on the same instance of an inputstream. That makes sense.Unvalued
nice answer! unfortunatly markSupported is set to false in my case :(Lethalethal
@zhar Such InputStreams (that do not support mark/reset) can be simply wrapped into BufferedInputStream.Prowler

© 2022 - 2024 — McMap. All rights reserved.