summaryrefslogtreecommitdiffstats
path: root/jni_jpegstream/src/jpegstream.cpp
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2013-06-28 20:02:54 -0700
committerRuben Brunk <rubenbrunk@google.com>2013-07-11 13:41:29 -0700
commit8d8d5cf2943da78ca5f84d1729b081312c031e6a (patch)
treef4c60b00a469733ff11901bd8fdc030c8f537f5c /jni_jpegstream/src/jpegstream.cpp
parent3ea8558300780ca5269d75230f78eadf4100876c (diff)
downloadandroid_packages_apps_Snap-8d8d5cf2943da78ca5f84d1729b081312c031e6a.tar.gz
android_packages_apps_Snap-8d8d5cf2943da78ca5f84d1729b081312c031e6a.tar.bz2
android_packages_apps_Snap-8d8d5cf2943da78ca5f84d1729b081312c031e6a.zip
Added jpeg streaming classes.
- Provides streaming operations for decompressing/compressing JPEG files. - Allows pixel operations to be performed on large JPEG images without holding the entire bitmap in memory. Change-Id: I597ddf282b59d2ba6d6bca4722208121e3728f94
Diffstat (limited to 'jni_jpegstream/src/jpegstream.cpp')
-rw-r--r--jni_jpegstream/src/jpegstream.cpp377
1 files changed, 377 insertions, 0 deletions
diff --git a/jni_jpegstream/src/jpegstream.cpp b/jni_jpegstream/src/jpegstream.cpp
new file mode 100644
index 000000000..3b9a6830b
--- /dev/null
+++ b/jni_jpegstream/src/jpegstream.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "error_codes.h"
+#include "jni_defines.h"
+#include "jpeg_writer.h"
+#include "jpeg_reader.h"
+#include "jpeg_config.h"
+#include "outputstream_wrapper.h"
+#include "inputstream_wrapper.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static jint OutputStream_setup(JNIEnv* env, jobject thiz, jobject out,
+ jint width, jint height, jint format, jint quality) {
+ // Get a reference to this object's class
+ jclass thisClass = env->GetObjectClass(thiz);
+ if (env->ExceptionCheck() || thisClass == NULL) {
+ return J_EXCEPTION;
+ }
+ // Get field for storing C pointer
+ jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+ if (NULL == fidNumber || env->ExceptionCheck()) {
+ return J_EXCEPTION;
+ }
+
+ // Check size
+ if (width <= 0 || height <= 0) {
+ return J_ERROR_BAD_ARGS;
+ }
+ Jpeg_Config::Format fmt = static_cast<Jpeg_Config::Format>(format);
+ // Check format
+ switch (fmt) {
+ case Jpeg_Config::FORMAT_GRAYSCALE:
+ case Jpeg_Config::FORMAT_RGB:
+ case Jpeg_Config::FORMAT_RGBA:
+ case Jpeg_Config::FORMAT_ABGR:
+ break;
+ default:
+ return J_ERROR_BAD_ARGS;
+ }
+
+ uint32_t w = static_cast<uint32_t>(width);
+ uint32_t h = static_cast<uint32_t>(height);
+ int32_t q = static_cast<int32_t>(quality);
+ // Clamp quality to (0, 100]
+ q = (q > 100) ? 100 : ((q < 1) ? 1 : q);
+
+ JpegWriter* w_ptr = new JpegWriter();
+
+ // Do JpegWriter setup.
+ int32_t errorFlag = w_ptr->setup(env, out, w, h, fmt, q);
+ if (env->ExceptionCheck() || errorFlag != J_SUCCESS) {
+ delete w_ptr;
+ return errorFlag;
+ }
+
+ // Store C pointer for writer
+ env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(w_ptr));
+ if (env->ExceptionCheck()) {
+ delete w_ptr;
+ return J_EXCEPTION;
+ }
+ return J_SUCCESS;
+}
+
+static jint InputStream_setup(JNIEnv* env, jobject thiz, jobject dimens,
+ jobject in, jint format) {
+ // Get a reference to this object's class
+ jclass thisClass = env->GetObjectClass(thiz);
+ if (env->ExceptionCheck() || thisClass == NULL) {
+ return J_EXCEPTION;
+ }
+ jmethodID setMethod = NULL;
+
+ // Get dimensions object setter method
+ if (dimens != NULL) {
+ jclass pointClass = env->GetObjectClass(dimens);
+ if (env->ExceptionCheck() || pointClass == NULL) {
+ return J_EXCEPTION;
+ }
+ setMethod = env->GetMethodID(pointClass, "set", "(II)V");
+ if (env->ExceptionCheck() || setMethod == NULL) {
+ return J_EXCEPTION;
+ }
+ }
+ // Get field for storing C pointer
+ jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+ if (NULL == fidNumber || env->ExceptionCheck()) {
+ return J_EXCEPTION;
+ }
+ Jpeg_Config::Format fmt = static_cast<Jpeg_Config::Format>(format);
+ // Check format
+ switch (fmt) {
+ case Jpeg_Config::FORMAT_GRAYSCALE:
+ case Jpeg_Config::FORMAT_RGB:
+ case Jpeg_Config::FORMAT_RGBA:
+ case Jpeg_Config::FORMAT_ABGR:
+ break;
+ default:
+ return J_ERROR_BAD_ARGS;
+ }
+
+ JpegReader* r_ptr = new JpegReader();
+ int32_t w = 0, h = 0;
+ // Do JpegReader setup.
+ int32_t errorFlag = r_ptr->setup(env, in, &w, &h, fmt);
+ if (env->ExceptionCheck() || errorFlag != J_SUCCESS) {
+ delete r_ptr;
+ return errorFlag;
+ }
+
+ // Set dimensions to return
+ if (dimens != NULL) {
+ env->CallVoidMethod(dimens, setMethod, static_cast<jint>(w),
+ static_cast<jint>(h));
+ if (env->ExceptionCheck()) {
+ delete r_ptr;
+ return J_EXCEPTION;
+ }
+ }
+ // Store C pointer for reader
+ env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(r_ptr));
+ if (env->ExceptionCheck()) {
+ delete r_ptr;
+ return J_EXCEPTION;
+ }
+ return J_SUCCESS;
+}
+
+static JpegWriter* getWPtr(JNIEnv* env, jobject thiz, jfieldID* fid) {
+ jclass thisClass = env->GetObjectClass(thiz);
+ if (env->ExceptionCheck() || thisClass == NULL) {
+ return NULL;
+ }
+ jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+ if (NULL == fidNumber || env->ExceptionCheck()) {
+ return NULL;
+ }
+ jlong ptr = env->GetLongField(thiz, fidNumber);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ // Get writer C pointer out of java field.
+ JpegWriter* w_ptr = reinterpret_cast<JpegWriter*>(ptr);
+ if (fid != NULL) {
+ *fid = fidNumber;
+ }
+ return w_ptr;
+}
+
+static JpegReader* getRPtr(JNIEnv* env, jobject thiz, jfieldID* fid) {
+ jclass thisClass = env->GetObjectClass(thiz);
+ if (env->ExceptionCheck() || thisClass == NULL) {
+ return NULL;
+ }
+ jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+ if (NULL == fidNumber || env->ExceptionCheck()) {
+ return NULL;
+ }
+ jlong ptr = env->GetLongField(thiz, fidNumber);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ // Get reader C pointer out of java field.
+ JpegReader* r_ptr = reinterpret_cast<JpegReader*>(ptr);
+ if (fid != NULL) {
+ *fid = fidNumber;
+ }
+ return r_ptr;
+}
+
+static void OutputStream_cleanup(JNIEnv* env, jobject thiz) {
+ jfieldID fidNumber = NULL;
+ JpegWriter* w_ptr = getWPtr(env, thiz, &fidNumber);
+ if (w_ptr == NULL) {
+ return;
+ }
+ // Update environment
+ w_ptr->updateEnv(env);
+ // Destroy writer object
+ delete w_ptr;
+ w_ptr = NULL;
+ // Set the java field to null
+ env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(w_ptr));
+}
+
+static void InputStream_cleanup(JNIEnv* env, jobject thiz) {
+ jfieldID fidNumber = NULL;
+ JpegReader* r_ptr = getRPtr(env, thiz, &fidNumber);
+ if (r_ptr == NULL) {
+ return;
+ }
+ // Update environment
+ r_ptr->updateEnv(env);
+ // Destroy the reader object
+ delete r_ptr;
+ r_ptr = NULL;
+ // Set the java field to null
+ env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(r_ptr));
+}
+
+static jint OutputStream_writeInputBytes(JNIEnv* env, jobject thiz,
+ jbyteArray inBuffer, jint offset, jint inCount) {
+ JpegWriter* w_ptr = getWPtr(env, thiz, NULL);
+ if (w_ptr == NULL) {
+ return J_EXCEPTION;
+ }
+ // Pin input buffer
+ jbyte* in_buf = (jbyte*) env->GetByteArrayElements(inBuffer, 0);
+ if (env->ExceptionCheck() || in_buf == NULL) {
+ return J_EXCEPTION;
+ }
+
+ int8_t* in_bytes = static_cast<int8_t*>(in_buf);
+ int32_t in_len = static_cast<int32_t>(inCount);
+ int32_t off = static_cast<int32_t>(offset);
+ in_bytes += off;
+ int32_t written = 0;
+
+ // Update environment
+ w_ptr->updateEnv(env);
+ // Write out and unpin buffer.
+ written = w_ptr->write(in_bytes, in_len);
+ env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_ABORT);
+ return written;
+}
+
+static jint InputStream_readDecodedBytes(JNIEnv* env, jobject thiz,
+ jbyteArray inBuffer, jint offset, jint inCount) {
+ JpegReader* r_ptr = getRPtr(env, thiz, NULL);
+ if (r_ptr == NULL) {
+ return J_EXCEPTION;
+ }
+ // Pin input buffer
+ jbyte* in_buf = (jbyte*) env->GetByteArrayElements(inBuffer, 0);
+ if (env->ExceptionCheck() || in_buf == NULL) {
+ return J_EXCEPTION;
+ }
+ int8_t* in_bytes = static_cast<int8_t*>(in_buf);
+ int32_t in_len = static_cast<int32_t>(inCount);
+ int32_t off = static_cast<int32_t>(offset);
+ int32_t read = 0;
+
+ // Update environment
+ r_ptr->updateEnv(env);
+ // Read into buffer
+ read = r_ptr->read(in_bytes, off, in_len);
+
+ // Unpin buffer
+ if (read < 0) {
+ env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_ABORT);
+ } else {
+ env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_COMMIT);
+ }
+ return read;
+}
+
+static jint InputStream_skipDecodedBytes(JNIEnv* env, jobject thiz,
+ jint bytes) {
+ if (bytes <= 0) {
+ return J_ERROR_BAD_ARGS;
+ }
+ JpegReader* r_ptr = getRPtr(env, thiz, NULL);
+ if (r_ptr == NULL) {
+ return J_EXCEPTION;
+ }
+
+ // Update environment
+ r_ptr->updateEnv(env);
+ int32_t skip = 0;
+ // Read with null buffer to skip
+ skip = r_ptr->read(NULL, 0, bytes);
+ return skip;
+}
+
+static const char *outClassPathName =
+ "com/android/gallery3d/jpegstream/JPEGOutputStream";
+static const char *inClassPathName =
+ "com/android/gallery3d/jpegstream/JPEGInputStream";
+
+static JNINativeMethod writeMethods[] = { { "setup",
+ "(Ljava/io/OutputStream;IIII)I", (void*) OutputStream_setup }, {
+ "cleanup", "()V", (void*) OutputStream_cleanup }, { "writeInputBytes",
+ "([BII)I", (void*) OutputStream_writeInputBytes } };
+
+static JNINativeMethod readMethods[] = { { "setup",
+ "(Landroid/graphics/Point;Ljava/io/InputStream;I)I",
+ (void*) InputStream_setup }, { "cleanup", "()V",
+ (void*) InputStream_cleanup }, { "readDecodedBytes", "([BII)I",
+ (void*) InputStream_readDecodedBytes }, { "skipDecodedBytes", "(I)I",
+ (void*) InputStream_skipDecodedBytes } };
+
+static int registerNativeMethods(JNIEnv* env, const char* className,
+ JNINativeMethod* gMethods, int numMethods) {
+ jclass clazz;
+ clazz = env->FindClass(className);
+ if (clazz == NULL) {
+ LOGE("Native registration unable to find class '%s'", className);
+ return JNI_FALSE;
+ }
+ if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+ LOGE("RegisterNatives failed for '%s'", className);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ LOGE("Error: GetEnv failed in JNI_OnLoad");
+ return -1;
+ }
+ if (!registerNativeMethods(env, outClassPathName, writeMethods,
+ sizeof(writeMethods) / sizeof(writeMethods[0]))) {
+ LOGE("Error: could not register native methods for JPEGOutputStream");
+ return -1;
+ }
+ if (!registerNativeMethods(env, inClassPathName, readMethods,
+ sizeof(readMethods) / sizeof(readMethods[0]))) {
+ LOGE("Error: could not register native methods for JPEGInputStream");
+ return -1;
+ }
+ // cache method IDs for OutputStream
+ jclass outCls = env->FindClass("java/io/OutputStream");
+ if (outCls == NULL) {
+ LOGE("Unable to find class 'OutputStream'");
+ return -1;
+ }
+ jmethodID cachedWriteFun = env->GetMethodID(outCls, "write", "([BII)V");
+ if (cachedWriteFun == NULL) {
+ LOGE("Unable to find write function in class 'OutputStream'");
+ return -1;
+ }
+ OutputStreamWrapper::setWriteMethodID(cachedWriteFun);
+
+ // cache method IDs for InputStream
+ jclass inCls = env->FindClass("java/io/InputStream");
+ if (inCls == NULL) {
+ LOGE("Unable to find class 'InputStream'");
+ return -1;
+ }
+ jmethodID cachedReadFun = env->GetMethodID(inCls, "read", "([BII)I");
+ if (cachedReadFun == NULL) {
+ LOGE("Unable to find read function in class 'InputStream'");
+ return -1;
+ }
+ jmethodID cachedSkipFun = env->GetMethodID(inCls, "skip", "(J)J");
+ if (cachedSkipFun == NULL) {
+ LOGE("Unable to find skip function in class 'InputStream'");
+ return -1;
+ }
+ InputStreamWrapper::setReadSkipMethodIDs(cachedReadFun, cachedSkipFun);
+ return JNI_VERSION_1_6;
+}
+
+#ifdef __cplusplus
+}
+#endif