skgmn / RapidDecoder

Simplified bitmap decoding and scaling for Android
Apache License 2.0
260 stars 43 forks source link

JavaDocs ? Available features? #1

Open AndroidDeveloperLB opened 10 years ago

AndroidDeveloperLB commented 10 years ago

I would like to know better about this library. Are there any JavaDocs ? any list of available features (besides the wiki page) ?

For example, I would like to know if it supports WebP encoding/decoding, if it can have face detection, if it supports direct downsampling of an internet image link (instead of creating 2 input streams or download the file and then check it out),...

Also, I would like to know if using this library ensures that the bitmap isn't held in the heap till you tell it to.

skgmn commented 10 years ago

It's true that this library doesn't contain kind descriptions about features and apis it provides. I'll work on it gradually.

To answer your questions:

  1. WebP is not supported yet, but it's nice idea.
  2. Face detection is not on the plan. Why not use FaceDetector?
  3. Of course you can downsample images from a stream. BitmapDecoder has been intended to achieve such that jobs.
  4. I couldn't get your last question exactly, but BitmapDecoder really doesn't hold any bitmaps before you call decode() or bitmap(). It may decode bounds of a bitmap if necessary, but never pre-decode actual raster pixels.
AndroidDeveloperLB commented 10 years ago

1.cool. thanks.

2.FaceDetector works on the java side. if you add it on the JNI side (C/C++) , this could allow you to detect faces without the worry of OOM (for too large images). This way, if an app wishes to crop a huge image based on the faces within it, it could do it all on the JNI side, and after cropping, it could show it on the Java side.

  1. The reason I say it is that on Java, in order to downsample, you first need to get the info of the image (width & height) , decide how much to downsample, and then re-read the file from the beginning, which means you need to use inputStream twice. I've written about it here: http://stackoverflow.com/questions/17774442/how-to-get-bitmap-information-and-then-decode-bitmap-from-internet-inputstream What I've done there works only on some cases. I think it won't work when the data is too much to hold.
  2. This is the most crucial question actually. Since Java is limited in heap memory, large bitmaps cannot be held. The only way to hold huge bitmaps is via JNI, so what I asked is whether your library allows doing operations on a huge bitmap on the JNI "world" and only when I'm done with it, I could take a bitmap to the Java "world" (maybe even write to a file before, if I want to).
skgmn commented 10 years ago

I verified your question and the problem on stackoverflow, and I solved it by creating a new input stream class with buffering feature. It'll be updated soon.

I don't know whether large memory can be held in JNI context. This library decodes bitmap line by line, so that it could handle large image without OOM.

And I think face detection is not suitable for this. It will require OpenCV or something to be implemented, but that will make the binary fat and it seems not so efficient. But it will be good to provide some interfaces that enable developers to manipulate image data line by line, so that they can implement their own detection routines.

AndroidDeveloperLB commented 10 years ago

about the inputStream, you should try to check some websites and on some old android devices. as i've reported, what i've made doesn't always work.

about large memory, you can just try it out. take a huge image on the Internet and see if an "old" device can handle it. i've tested it on my SGS3 , and I can easily cause OOM if I want to . remember that a bitmap takes at least 4_width_height bytes , so if the heap is of size 64MB, you can use an image that is of size 6000*6000 (which is ~144MB) .

about face detection, ok, it was just a suggestion in case it is possible to harness what googe has inside of its source code.

skgmn commented 10 years ago

Updated. The code below should work now.

mImageView = (ImageView) findViewById(R.id.image_view);

new AsyncTask<Object, Object, Bitmap>() {
    @Override
    protected Bitmap doInBackground(Object... params) {
        try {
            InputStream in = new URL("http://farm6.staticflickr.com/5172/5588953445_51dcf922aa_o.jpg")
                .openConnection()
                .getInputStream();

            return BitmapDecoder.from(in).scaleBy(1 / 8f).decode();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    protected void onPostExecute(Bitmap result) {
        if (result == null) {
            Log.e(LOG_TAG, "Couldn't load an image.");
        } else {
            mImageView.setImageBitmap(result);
        }
    }
}.execute();
AndroidDeveloperLB commented 10 years ago

This wasn't my intention of the question, but it's good to have too. what you've shown can be done on java side without any JNI involved: either download the file and then use it, or use the inputStream twice (once for getting resolution and once for real downsampling). for the part of downsampling, you could use this: http://stackoverflow.com/a/17773344/878126 , which allows you to downsample even by values that are not power of 2 .

What I asked is whether we can do a full decode of the image on the JNI side, and add a function there to play with it (for example setting all pixels to be only of blue colors), and when finished, you could either export the bitmap to a file (as-is) or downsample it for Java-bitmap instead (or both).

BTW, about scaling, wouldn't it be better to use two parameters instead - nominator and denominator ?

skgmn commented 10 years ago

You know, neither inDensity nor inTargetDensity are intended to do that. The method you did is not different from scaling image after full decoding. I didn't test it but it will not work with large images.

And now I understand what you really want to do. It may be a nice feature dealing large bitmap which cannot be handled usually, but it is not a good idea to occupy big memory in any way. We should keep design principles Android provides. This feature may be implemented using file that keeps whole decoded data and caching only partial data when it's necessary at the moment.

AndroidDeveloperLB commented 10 years ago

Yes, I know I made a trick, and also wrote about it. I also wrote a merged method that uses both my way and Google's way, since their method uses less memory and is faster (but it doesn't support downsampling of all possible values).

If a Java-based app needs to handle a large image (even rotate it), it cannot do it in case the heap is too small since the current ways create 2 huge bitmaps in the process. That's why I made a library that handles at least the part of having 2 bitmaps at the same time (though the initial one will still be huge) : http://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations

It's a very basic library, and all it does it holding a large bitmap within the "JNI-world" , while allowing you to do all the work on the "JNI-world", and only when you are done, you continue to the "Java-world". Sadly, it misses the part of decoding, so that's why I'm searching for this solution too. I've also asked about it here: http://blog.translucentcomputing.com/2012/05/jni-android.html

I hope I will find the way (and time) to also add this to my tiny library.