2

I'm trying to decode an inputstream to bitmap, the code is so simple :

Bitmap myBitmap = BitmapFactory.decodeStream(myStream);

BUT the quality of outputed bitmap is too low (sometimes, and sometimes the quality is good).

also the source has a good quality image.

i tried to play with Bitmap options but nothing changed:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap myBitmap = BitmapFactory.decodeStream(myStream, null, options);

so, how can i get the full quality bitmap?

Update 1:

I use this picture for an animation, like below:

coverAnimationImage.post(new Runnable()
{
    Override
    public void run()
    {
        try
        {
            InputStream coverStream = getCoverStream();
            if(coverStream != null)
            {
                bookCover = BitmapFactory.decodeStream(coverStream);
            }
        }
        catch (Exception e)
        {
            //  no cover
        }
        coverAnimationImage.setImageBitmap(bookCover);
        mBackground = new ColorDrawable(Color.BLACK);
        if(Build.VERSION.SDK_INT >= 16)
        {
            coverAnimationLayout.setBackground(mBackground);
        }
        else
        {
           coverAnimationLayout.setBackgroundDrawable(mBackground);
        }
        if (flag)
        {
            ViewTreeObserver observer = coverAnimationImage.getViewTreeObserver();
            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
            {
                @Override
                public boolean onPreDraw()
                {
                    coverAnimationImage.getViewTreeObserver().removeOnPreDrawListener(this);
                    int[] screenLocation = new int[2];
                    coverAnimationImage.getLocationOnScreen(screenLocation);
                    mLeftDelta = coverLeft - (screenLocation[0]);
                    mTopDelta = coverTop - (screenLocation[1]);
                    mWidthScale = (float) coverWidth / coverAnimationImage.getWidth();
                    mHeightScale = (float) coverHeight / coverAnimationImage.getHeight();
                    runEnterAnimation();
                    return true;
                }
            });
        }
    }
});

I think when i run the animation the BitmapFactory.decodeStream isn't finished it's job! is it possible? or any idea whats happening here?

Update 2: the image info

enter image description here

Update 3:

low quality image:

enter image description here

high quality:

enter image description here

memory monitor:

enter image description here

YouTube Video:

android BitmapFactory.decodeStream low quality

Update 4:

the code of getCoverStream :

protected InputStream getCoverStream() 
{    
    String fileName = getCoverAddress();
    InputStream in = null;
    ZipEntry containerEntry = mZip.getEntry(fileName);
    if (containerEntry != null) 
    {
        try 
        {
            in = mZip.getInputStream(containerEntry);
        } 
        catch (IOException e) 
        {
            Log.e(TAG, "Error reading zip file " + fileName, e);
        }
    }

    if (in == null) 
    {
        Log.e(TAG, "Unable to find file in zip: " + fileName);
    }

    return in;
}
mehdok
  • 1,499
  • 4
  • 29
  • 54
  • The standard approach should work... DecodeStream will decode full quality graphics by default. I'm wondering if your resource folders are correctly configured. For example, if you place a high quality graphic in the 'ldpi' folder, and low quality graphics in the 'xxhdpi' folder, the environment may think it is choosing a high quality graphic, but ends up pulling out a low quality graphic. Perhaps we could better help if you told us the image resolutions being used in each of the asset folders? (ldpi / mdpi / hdpi / xhdpi / xxhdpi) – 1owk3y Jun 02 '15 at 05:15
  • @1owk3y The image i used to decode is not in the drawable folders. the image extracted as stream from an epub book. i can see the image has a good qality. – mehdok Jun 02 '15 at 05:49
  • Is the image 'progressive'? Perhaps it is only stopping as soon as it gets the first sample pass (low quality). Try a non-progressive image? (just eliminating the possibility before we dig further). If using a non-progressive image fixes the issue, then you'll know it's stopping after the first pass (and can find how to tell Android how to not stop after the first pass. Sorry, I'd look this up myself right now but I'm in transit) – 1owk3y Jun 02 '15 at 09:25
  • @1owk3y, ok, the image is a `png` , i tested it with exiftool [http://www.sno.phy.queensu.ca/~phil/exiftool/](http://www.sno.phy.queensu.ca/~phil/exiftool/) and posted the result to original question. the thing is the quality is random, suppose the first time i ran the code the quality is low and 4rd time is good. – mehdok Jun 02 '15 at 10:55
  • I got a test app going with an image downloading and decoding using bitmapFactory, but it seems to show with consistent quality. When you say the quality varies, is this across different devices? Or virtual devices with different DPI's? DPI would definitely play a factor. Also, check the dimensions of the image being downloaded; is it always the same? – 1owk3y Jun 03 '15 at 16:05
  • @1owk3y the device i tested is `Asus memo pad hd 7`, the quality varies happens from time to time. i tested on other devices like `nexus 5` and same result happens. the image source is the same every time, nothing changed during tests. – mehdok Jun 03 '15 at 16:29
  • Still not able to replicate this. I just can't get an environment going where the quality *varies* between loads. Should I upload my example project? My streamed image always loads perfectly. What is your basis for the quality loss observation; are you able to provide a low and high quality screenshot so we can observe the re sampling? Does changing the image source provide better effects? Are you seeing memory limit warnings in your LogCat? Does stripping the functionality OUT of the app into a new app improve the issue? (you may have memory issues in your original app) – 1owk3y Jun 04 '15 at 04:17
  • @1owk3y For screen shot please see update 3 in question, i also posted a memory monitor shot, i'm using `large heap` flag, so this amount of ram is normal. i also posted a video on youtube, the overall quality is a little low because of recording, but the difference is obvious, the first time quality is low and the second time it's good, sometimes the good quality appears after 4rd time. for some of this book the quality of encoding is always high, this low quality happens for some book. Now i'm going to strip other functionality to see what is happening. – mehdok Jun 04 '15 at 05:00
  • @1owk3y Ok, I stripped other functionality, Now i have a `gridview` with some items that by clicking start the animation, and the variety in quality for **some book** still happening. – mehdok Jun 04 '15 at 05:10
  • can you post the code for getCoverStream(); or give us some more information about it? Where is the image being loaded from? – samgak Jun 05 '15 at 05:54
  • @samgak ok the image will extract from an ebup book, the code for `getCoverStream` is posted on update 4 in question, if you more code please let me know. – mehdok Jun 05 '15 at 06:13
  • Try mZip.getSize(); mZip.getCompressedSize(); mZip.getCrc() in LogCat. Do the results vary on download attempts with different qualities? I'm trying to determine if the zip download is stopping after a certain amount of time, gives up, and then just displays the information it has... or something. – 1owk3y Jun 05 '15 at 07:42
  • 1
    @1owk3y , ok i have done what you said and i saw that sometimes the `getCoverStream` wont call at all and as result the quality is low, the problem is i pass a preview of cover as an extra to the second activity and sometimes the activity use that preview for animation. You really helped me find the original problem so i want to give the bounty to you. Just post an answer and i will do that. – mehdok Jun 05 '15 at 08:41

1 Answers1

2

It may not actually be an issue with BitmapFactory.decodeStream(), because decodeStream decodes full resolution data by default.

We see that you're using ZipEntry. It could be an issue of the stream not fully downloading, or the stream (getCoverStream) not being invoked.

Try mZip.getSize(); mZip.getCompressedSize(); mZip.getCrc(); in LogCat. Do the results vary on download attempts with different qualities? I'm trying to determine if the zip download is stopping after a certain amount of time, gives up, and then just displays the information it has etc

1owk3y
  • 1,115
  • 1
  • 15
  • 30