9

background

On some apps, it is important to handle large images without OOM and also quickly.

For this, JNI (or renderscript, which sadly lacks on documentation) can be a nice solution.

In the past, i've succeeded using JNI for rotating huge bitmaps while avoiding OOM (link here , here and here). it was a nice (yet annoyingly hard) experience, but in the end it worked.

the problem

the android framework has plenty of functions to handle bitmaps, but i have no idea what is the situation on the JNI side.

I already know how to pass a bitmap from android's "java world" to the "JNI world" and back.

What i don't know is which functions I can use on the JNI side to help me with bitmaps.

I wish to be able to do all image operations (including decoding) on JNI, so that I won't need to worry about OOM when presented with large images, and in the end of the process, I could convert the data to Java-bitmap (to show the user) and/or write it to a file.

again, i don't want to convert the data on the JNI side to a java bitmap just to be able to run those operations.

As it turns out, there are some libraries that offer many functions (like JavaCV), but they are quite large and I'm not quite sure about their features and if they really do the decoding on the JNI-side, so I would prefer to be able to know what is possible via the built-in JNI function of Android instead.

the question

which functions are available for image manipulation on the JNI side on android?

for example, how could i run face detection on bitmaps, apply matrices, downsample bitmaps, scale bitmaps, and so on... ?

for some of the operations, i can already think of a way to implement them (scaling images is quite easy, and wikipedia can help a lot), but some are very complex.

even if i do implement the operations by myself, maybe others have made it much more efficiently, thinking of the so many optimizations that C/C++ can have.

am i really on my own when going to the JNI side of android, where i need to implement everythign from scratch?

just to make it clear, what i'm interested in is:

input bitmap on java -> image manipulation purely in JNI and C/C++ (no convertion to java objects whatsoever) ->output bitmap on java.

Community
  • 1
  • 1
android developer
  • 114,585
  • 152
  • 739
  • 1,270
  • Have you by any chance taken a look at [OpenCV](http://opencv.org/) and found it lacking in some way? – Samuel Audet Jul 27 '13 at 05:28
  • 1
    i've asked about what android has to offer. in addition, according to what i've read, this library requires that the end user himself would install their library as an app : https://play.google.com/store/apps/details?id=org.opencv.engine . i'm not sure why it works this way (size of library?), but asking the user to install another app could be annoying. i've heard the library is too "heavy" on resources, even on my galaxy s3 device when i've tried the sample app from sony: http://developer.sonymobile.com/knowledge-base/tutorials/android_tutorial/get-started-with-opencv-on-android/ – android developer Jul 27 '13 at 08:03
  • OpenCV is available under a BSD style license, so it's possible to copy/paste only the parts you need... In any case, if your question is about using Android functionality, the answer is obviously yes: We can use everything through JNI. If you want something efficient, then that's another question. You need to clarify your priorities. – Samuel Audet Jul 27 '13 at 12:46
  • free to do whatever you wish to it? they only ask to keep the license documentation and not to mention their names. nice. anyway, i never used this library and i think it's quite complex to "dissect" just what i need from it. about JNI in android, i know i can implement everything, the question is what android has that can help with it. for example, on the java side, we have face detection. do we have the same on JNI side? if android has all the basic things on JNI as it has on java, i think i'll prefer using it instead of "dissecting" other libraries – android developer Jul 27 '13 at 13:29
  • Sure, we can access **everything** with JNI. – Samuel Audet Jul 28 '13 at 02:06
  • really? can you please show me some examples? for example, what is the C/C++ equivalent function on android for face detection? so far, the only functions i've found is for locking ,unlocking and getting information of bitmaps. – android developer Jul 28 '13 at 05:20
  • We have the [FaceDetector](http://developer.android.com/reference/android/media/FaceDetector.html) class, so we can create an instance with [NewObject](http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp4517). I assume you can figure out the rest? – Samuel Audet Jul 29 '13 at 02:49
  • the class you've just shown is a java class, which takes java objects as parameters. i've asked about a C/C++ class, which takes C/C++ parameters. something that works on C/C++ that doesn't need any conversion to java in order to work. i've moved to JNI so that i could do the operations in C/C++, otherwise i would keep using the java functions... – android developer Jul 29 '13 at 06:29
  • Right, so if you don't want to use JNI, you should revise your question to mention as much. – Samuel Audet Jul 29 '13 at 08:00
  • you've got it all wrong. i want to use JNI. i don't want to use java for the image manipulation. during image manipulation, i don't want to create temporary java objects for java functions. only JNI. only in the end, i will convert the output to java objects. i've edited the question and added it at the bottom. – android developer Jul 29 '13 at 09:40
  • JNI = Java Native Interface. Either you want to use Java and JNI, or you don't. There is no in between. – Samuel Audet Jul 29 '13 at 09:47
  • i use java, only that for the bitmap manipulation i want to use JNI, which will runc C/C++ code for the operations, and only in the end of the process, i will convert the data back to java. this is the part in between - the JNI using C/C++ . – android developer Jul 29 '13 at 10:57

2 Answers2

5

"built-in JNI function of Android" is kind of oxymoron. It's technically correct that many Android Framework Java classes use JNI somewhere down the chain to invoke native libraries.

But there are three reservations regarding this statement.

  1. These are "implementation details", and are subject to change without notice in any next release of Android, or any fork (e.g. Kindle), or even OEM version which is not regarded a "fork" (e.g. built by Samsung, or for Quallcom SOC).

  2. The way native methods are implemented in core Java classes is different from the "classical" JNI. These methods are preloaded and cached by the JVM and are therefore do not suffer from most of the overhead typical for JNI calls.

  3. There is nothing your Java or native code can do to interact directly with the JNI methods of other classes, especially classes that constitute the system framework.

All this said, you are free to study the source code of Android, to find the native libraries that back specific classes and methods (e.g. face detection), and use these libraries in your native code, or build a JNI layer of your own to use these libraries from your Java code.


To give a specific example, face detection in Android is implemented through the android.media.FaceDetector class, which loads libFFTEm.so. You can look at the native code, and use it as you wish. You should not assume that libFFTEm.so will be present on the device, or that the library on device will have same API.

But in this specific case, it's not a problem, because all work of neven is entirely software based. Therefore you can copy this code in its entirety, or only relevant parts of it, and make it part of your native library. Note that for many devices you can simply load and use /system/lib/libFFTEm.so and never feel discomfort, until you encounter a system that will misbehave.

One noteworthy conclusion you can make from reading the native code, is that the underlying algorithms ignore the color information. Therefore, if the image for which you want to find face coordinates comes from YUV source, you can avoid a lot of overhead if you call

// run detection
btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height);

int numberOfFaces = 0;
if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) {
    numberOfFaces = btk_FaceFinder_faces(hfd);
} else {
    ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR.\n");
}

directly with your YUV (or Y) byte array, instead of converting it to RGB and back to YUV in android.media.FaceDetector.findFaces(). If your YUV buffer comes from Java, you can build your own class YuvFaceDetector which will be a copy of android.media.FaceDetector with the only difference that YuvFaceDetector.findFaces() will take Y (luminance) values only instead of a Bitmap, and avoid the RGB to Y conversion.


Some other situations are not as easy as this. For example, the video codecs are tightly coupled to the hardware platform, and you cannot simply copy the code from libstagefright.so to your project. Jpeg codec is a special beast. In modern systems (IIRC, since 2.2), you can expect /system/lib/libjpeg.so to be present. But many platforms also have much more efficient HW implementations of Jpeg codecs through libstagefright.so or OpenMAX, and often these are used in android.graphics.Bitmap.compress() and android.graphics.BitmapFactory.decode***() methods.

And there also is an optimized libjpeg-turbo, which has its own advantages over /system/lib/libjpeg.so.

Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • So there is no official way to decode images (for example) on C/C++ ? only via Java? so the whole idea that google said it supports both languages isn't quite true. they support the API of the java part, and for C/C++ you are on your own, and you might even have compatibility problems with some devices... – android developer Feb 06 '14 at 11:41
  • @androiddeveloper: "So there is no official way to decode images (for example) on C/C++ ? only via Java?" -- you use a library to decode images in any of those languages, or pretty much any other programming language. Where the library comes from will vary. "so the whole idea that google said it supports both languages isn't quite true" -- "supports" does not imply "identical support". Please read [the NDK documentation](https://developer.android.com/tools/sdk/ndk/index.html). – CommonsWare Feb 06 '14 at 13:49
  • NDK includes, among other subsystems, [native bitmap API](http://mobilepearls.com/labs/native-android-api/#bitmap). It is supported for Froyo (2.2) and higher versions of Android. Being official, it is guaranteed to work on all devices. – Alex Cohn Feb 06 '14 at 18:53
  • @AlexCohn it only has the ability to get the information of a decoded bitmap, to lock&unlock it. it can't decode the bitmap in any possible way. i've written that i used NDK and i've used those functions, but what i'm searching for is more than this... – android developer Feb 06 '14 at 20:18
  • @CommonsWare so what's the best next step from here, if I still wish to decode bitmaps on C/C++ ? will copying from android source code help? will it work on all android devices? do you know of any minimalistic, free third party library that should be able to do this task well? – android developer Feb 06 '14 at 20:20
  • @androiddeveloper: "so what's the best next step from here, if I still wish to decode bitmaps on C/C++ ?" -- `libjpeg` and `libpng` have been used on Linux for ages; presumably there is recipe for getting them to work on Android. Whether either of those are considered part of the NDK, for you to link to Android's own copy, would be covered by the NDK documentation. For other image transformations, look at ImageMagick, though I would not describe that is "minimalistic". Beyond that, again, look for Linux libraries. – CommonsWare Feb 06 '14 at 20:25
  • You are not asking me, but I would suggest libjbpeg-turbo with a wrapper that reuses the native Android code to produce a bitmap-compatible format. – Alex Cohn Feb 06 '14 at 20:26
  • wouldn't using any of those third party library also require me to do conversion between the formats? is there an android-"optimised"-library for this? or maybe that's what android OS does anyway when decoding images... ? – android developer Feb 06 '14 at 20:27
  • @CommonsWare: for all practical purposes, `libjpeg` may be considered a stable part of the system. But there is no official mention of it in NDK docs. – Alex Cohn Feb 06 '14 at 20:30
  • @androiddeveloper Are you find out better way? I'm using this way that download AOSP's some head file of skia library(android graphics library) , framework head file and libskia.so,libandroid_runtime.so ,then build in so.the c++ code look at the android BitmapFactory.cpp source code. – jhondge Oct 25 '14 at 09:26
  • @jhondge I don't understand the question. Did you figure out how to use Android's JNI code to decode bitmaps without using Java? – android developer Oct 25 '14 at 09:35
  • @androiddeveloper I was figure out an idea that download skia source code and some framework header file which GraphicsJNI::createBitmap method need and then use Skia Library to decode bitmap. there is my code. NOTE: this resolution is not exactly,because it's have a compatibility problem. `SkImageDecoder::DecodeFile(path, bitmap, prefConfig, SkImageDecoder::kDecodePixels_Mode);` `GraphicsJNI::createBitmap(env, bitmap, jmutable, NULL);` – jhondge Oct 27 '14 at 05:56
  • @jhondge Can you please post it on Github ? To show a POC ? – android developer Oct 27 '14 at 08:51
  • @androiddeveloper Okay I'm ASAP to upload to Github ([DecodeBitmapWithJNI](https://github.com/jhondge/DecodeBitmapWithJNI)):) But I think isn't a good way,As I'm learning the ropes around here, I welcome your advice. – jhondge Oct 27 '14 at 10:14
  • I would be surprised if `Java_com_everimaging_bitmap_BitmapUtil_nativeDecodeFile()` delivers any advantage over using Java to load a bitmap from file; the official API providing also scaling and other advanced options. – Alex Cohn Oct 27 '14 at 13:22
  • @jhondge I have no advice, as I'm really not an expert in bitmap decoding (and also not in JNI) . – android developer Oct 27 '14 at 15:20
  • @AlexCohn The main advantage is that you can load images without being constrained to the heap memory, thus reducing the chance of OOM. Another advantage is faster manipulations of bitmaps, and avoiding double bitmaps in some cases (like rotation of bitmaps). – android developer Oct 27 '14 at 17:00
1

It seems that your question is more about C/C++ image processing libraries than it is about Android per se. To that end, here are some other StackOverflow questions that might have information you'd find useful:

Fast Cross-Platform C/C++ Image Processing Libraries

C++ Image Processing Libraries

Community
  • 1
  • 1
jph
  • 2,181
  • 3
  • 30
  • 55