Libjpeg-Turbo for Android

libjpeg-turbo for android

Install Android NDK. Following instructions were verified with r8b, older versions may have problems, I don't know.

Get the Android sources for libjpeg-turbo from Benjamin Gaignard:

git clone git://git.linaro.org/people/tomgall/libjpeg-turbo/libjpeg-turbo.git -b linaro-android

In the libjpeg-turbo directory created by git, edit file Android.mk: after line 70, LOCAL_MODULE := libjpeg, add the following:

ifeq ($(notdir $(MAKECMDGOALS)),libjpeg.a)
LOCAL_SRC_FILES += $(libsimd_SOURCES_DIST)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := dummy
endif

Run ndk-build:

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk obj/local/armeabi/libjpeg.a

Profit!

PS: You may want the armeabi-v7a version:

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk APP_ABI=armeabi-v7a obj/local/armeabi-v7a/libjpeg.a

Or compile for ARM, to improve performance, add to command line:

LOCAL_ARM_MODE=arm

If your target has NEON support, add to command line:

LOCAL_ARM_NEON=true ARCH_ARM_HAVE_NEON=true

UPDATE: to get it work with Android NDK r15 and later, remove all references to libcutils from Android.mk.

How to add libjpeg-turbo Android NDK as static library

You receive the compile error because your CMake code doesn't specify the location of libjpeg header files. You can specify the directory containing the libjpeg headers by setting the INTERFACE_INCLUDE_DIRECTORIES property for the imported libjpeg target.

add_library( libjpeg STATIC IMPORTED )
set_target_properties( libjpeg
PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libjpeg/${ANDROID_ABI}/libjpeg.a
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/libjpeg/include
)

Note: You may have to modify the path to match where these headers reside on your machine.

With a couple other nit-picky notes (unrelated to the error), your updated CMake file may look something like this:

cmake_minimum_required(VERSION 3.4.1)

# You should always put the project directive at the top of your root CMakeLists.txt file.
project(MyProject)

add_library( libjpeg STATIC IMPORTED )
set_target_properties( libjpeg
PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libjpeg/${ANDROID_ABI}/libjpeg.a
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/libjpeg/include
)

# You can list multiple directories in one include_directories() call.
include_directories(
src/main/cpp/rapidjson/
src/main/cpp/Eigen
)

# Looks like this isn't used. Maybe you can remove it.
file(GLOB CPP_FILES "src/main/cpp/*.cpp")

add_library(
native-lib
SHARED

native-lib.cpp
common.cpp
archive.cpp
crc32.cpp
image.cpp
read_manifest.cpp
sensors.cpp
thumbnail.cpp
upf.cpp
upf-toolkit.cpp
write_manifest.cpp
write_upf.cpp
)
find_library(log-lib log)

# Always place the scoping argument (e.g. PUBLIC, PRIVATE) in this call.
target_link_libraries(native-lib PUBLIC libjpeg ${log-lib})

Integration or build instructions for libjpeg-turbo on Android

My bad, the file's in a branch in that repository.

Also found this info:

https://wiki.linaro.org/BenjaminGaignard/libjpeg-turboAndSkia

Is libjpeg always installed with Android?

Solution:
Thanks guys for the help, I was hoping libjpeg was accessible to my development but as pointed out is in Android though not public through the NDK.

So I spent sometime reading the spec for jpg and decided on writing a C decompresser from scratch until I fell upon jpgd by Rich Geldreich, and although C++ its single file implementation of jpeg decompresser in the public domain which Ive now used without any issues on Android.

He also has an accompanying jpge (encodeder) although surplus to my requirements for this project well worth noting.

My NO-JAVA application continues.

Solution:
C++ jpg Decompressor Android NDK

How to use jpeglib-turbo with android ndk?

Changes was required in tjDecompressHeader2 and we needed to use tjDecompressHeader3 in the library version, also we need to convert jbyteArray to unsigned char * and then back to jbyteArray in order to return a byte array to java, both of them can be observed in the code below.

#include <turbojpeg.h>
#include <jni.h>
#include <android/log.h>
#include <syslog.h>

JNIEXPORT jbyteArray
Java_com_serelay_jpegturbo_MainActivity_getImagePixelData( JNIEnv* env,
jobject this,
jbyteArray data,
jint dataLength)
{
long unsigned int _jpegSize=dataLength; //!< _jpegSize from above
unsigned char *_compressedImage; //!< _compressedImage from above
jboolean isCopy;

_compressedImage = (unsigned char*)(*env)->GetByteArrayElements(env, data,
&isCopy);
int width, height, jpegSubSamp, jpegColorSpace;
// int jpegSubSamp = TJSAMP_444;

tjhandle _jpegDecompressor = tjInitDecompress();

tjDecompressHeader3(_jpegDecompressor, _compressedImage, _jpegSize, &width,
&height, &jpegSubSamp, &jpegColorSpace);

long len = width * height * 4;
long pitch = width * 4;
syslog(LOG_CRIT, "====================");
syslog(LOG_CRIT, "jpegSize %lu", _jpegSize);

syslog(LOG_CRIT, "width %d", width);
syslog(LOG_CRIT, "height %d", height);
syslog(LOG_CRIT, "subsampl %d", jpegSubSamp);
syslog(LOG_CRIT, "colorSpace %d", jpegColorSpace);
syslog(LOG_CRIT, "len %lu", len);
syslog(LOG_CRIT, "pitch %lu", pitch);

syslog(LOG_CRIT, "====================");
syslog(LOG_CRIT, "===================0");

unsigned char* mumfer = (unsigned char*)malloc(len); //!< will contain the
decompressed image
syslog(LOG_CRIT, "===================1");

tjDecompress2(_jpegDecompressor, _compressedImage, _jpegSize, mumfer, width,
0, height, TJPF_RGBA, TJFLAG_FASTDCT);
syslog(LOG_CRIT, "===================2");

tjDestroy(_jpegDecompressor);
syslog(LOG_CRIT, "===================3");

// char array to byte array

jbyteArray array = (*env)->NewByteArray(env, len);
syslog(LOG_CRIT, "===================4");

//HERE I GET THE ERROR, I HAVE BEEN TRYING WITH len/2 and WORKS , PROBABLY
SOME BYTS ARE GETTING LOST.
(*env)->SetByteArrayRegion (env, array, 0, len, (jbyte*)(mumfer));
syslog(LOG_CRIT, "===================5");
return array;
}

Also in java we need to convert the byte[] to int[] in order to get the exact pixel color values which can be done with the help of the following function

public static int byteToColorInt(byte b) {
return b & 0xFF;
}

Android how to use libjpeg-turbo library through JNi example

You could create your own wrapper for the library in the native side if you need to perform it all from native code.
The steps are roughly these ones:

  • In the class where you call:

    System.loadLibrary("libjpeg");

You declare the native methods you need to call in the Java side, without providing any implementation:

public static native readJPEGFile();
  • Then you can use the javah command to create a C file with the implementation of your native funcions in the native side. That will be called when you call the native function in Java side. Notice the full path of the function and the parameters, that will be automatically generated by the javah command and should not be changed, otherwise it won't work. The result should be something like that:

     extern "C" {
    JNIEXPORT void JNICALL Java_com_android_packagename_GL2JNILib_readJPEGFile(JNIEnv * env, jobject obj);
    };

    JNIEXPORT void JNICALL Java_com_android_packagename_GL2JNILib_readJPEGFile(JNIEnv * env, jobject obj) {
    // Call your library's function
    }
  • After that you need to create a shared library in the jni folder (create it if it doesn't exist) containing your wrapper functions. You can do that creating an Android.mk file and running ndk-build to generate the shared library (.so file). A possible Android.mk could be like this one, you should check the names and dependencies though:

      LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := jpgturbo-wrapper
    LOCAL_CFLAGS := -Werror
    LOCAL_SRC_FILES := jpgturboWrapper.cpp
    LOCAL_C_INCLUDES := $(LOCAL_PATH)
    LOCAL_LDLIBS := -lm -llog -landroid
    LOCAL_STATIC_LIBRARIES := jpegturbo # write all the libraries your project depend on here, separated by white spaces
    include $(BUILD_SHARED_LIBRARY)
  • Now you can run ndk-build and the .so file will be generated and copied to its correspondent folder.

You can check the NDK documentation to start with that, and especially the samples they provide:
http://developer.android.com/tools/sdk/ndk/index.html

Sometimes is also a good idea to make a quick search on github to see if someone else took the pain before you to make work the same library, or just to see some more advanced examples than the official samples.

libjpeg turbo android jpeg compression

Finally i made it work, with the help of this question

Thanks to the user who posted it.

The code exactly meet my requirement and am able to compress images.

Note: but problem for compressing big images (> 5-30 MB)

UPDATE:-

Problem for compressing big images (> 5-30 MB) can be solved by specifying the resizing dimensions as 1/8 of its original width and height (minimum).

libjpeg-turbo for Android: how to organize runtime selection of NEON / non-NEON code?

An old question but I'll add to it anyway just in case. Someone did go into detail and one of the issues was dynamically selecting NEON. It is explained here: https://stackoverflow.com/a/20697814/712413.

The relevant section is item 4 to modify some lines in the init_simd() method.



Related Topics



Leave a reply



Submit