Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "BitmapSerializeUtils"
     18 
     19 #include <jni.h>
     20 #include <JNIHelp.h>
     21 
     22 #include <android/bitmap.h>
     23 #include <android/log.h>
     24 
     25 namespace android {
     26 
     27 #define RGBA_8888_COLOR_DEPTH 4
     28 
     29 static bool writeAllBytes(const int fd, void* buffer, const size_t byteCount) {
     30     char* writeBuffer = static_cast<char*>(buffer);
     31     size_t remainingBytes = byteCount;
     32     while (remainingBytes > 0) {
     33         ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
     34         if (writtenByteCount == -1) {
     35             if (errno == EINTR) {
     36                 continue;
     37             }
     38             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     39                     "Error writing to buffer: %d", errno);
     40             return false;
     41         }
     42         remainingBytes -= writtenByteCount;
     43         writeBuffer += writtenByteCount;
     44     }
     45     return true;
     46 }
     47 
     48 static bool readAllBytes(const int fd, void* buffer, const size_t byteCount) {
     49     char* readBuffer = static_cast<char*>(buffer);
     50     size_t remainingBytes = byteCount;
     51     while (remainingBytes > 0) {
     52         ssize_t readByteCount = read(fd, readBuffer, remainingBytes);
     53         if (readByteCount == -1) {
     54             if (errno == EINTR) {
     55                 continue;
     56             }
     57             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
     58                     "Error reading from buffer: %d", errno);
     59             return false;
     60         }
     61         remainingBytes -= readByteCount;
     62         readBuffer += readByteCount;
     63     }
     64     return true;
     65 }
     66 
     67 static void throwException(JNIEnv* env, const char* className, const char* message) {
     68     jclass exceptionClass = env->FindClass(className);
     69     env->ThrowNew(exceptionClass, message);
     70 }
     71 
     72 static void throwIllegalStateException(JNIEnv* env, char *message) {
     73     const char* className = "java/lang/IllegalStateException";
     74     throwException(env, className, message);
     75 }
     76 
     77 static void throwIllegalArgumentException(JNIEnv* env, char* message) {
     78     const char* className = "java/lang/IllegalArgumentException";
     79     throwException(env, className, message);
     80 }
     81 
     82 static void readBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
     83     // Read the info.
     84     AndroidBitmapInfo readInfo;
     85     bool read = readAllBytes(fd, (void*) &readInfo, sizeof(AndroidBitmapInfo));
     86     if (!read) {
     87         throwIllegalStateException(env, (char*) "Cannot read bitmap info");
     88         return;
     89     }
     90 
     91     // Get the info of the target bitmap.
     92     AndroidBitmapInfo targetInfo;
     93     int result = AndroidBitmap_getInfo(env, jbitmap, &targetInfo);
     94     if (result < 0) {
     95         throwIllegalStateException(env, (char*) "Cannot get bitmap info");
     96         return;
     97     }
     98 
     99     // Enforce we can reuse the bitmap.
    100     if (readInfo.width != targetInfo.width || readInfo.height != targetInfo.height
    101             || readInfo.stride != targetInfo.stride || readInfo.format != targetInfo.format
    102             || readInfo.flags != targetInfo.flags) {
    103         throwIllegalArgumentException(env, (char*) "Cannot reuse bitmap");
    104         return;
    105     }
    106 
    107     // Lock the pixels.
    108     void* pixels;
    109     result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
    110     if (result < 0) {
    111         throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
    112         return;
    113     }
    114 
    115     // Read the pixels.
    116     size_t byteCount = readInfo.stride * readInfo.height;
    117     read = readAllBytes(fd, (void*) pixels, byteCount);
    118     if (!read) {
    119         throwIllegalStateException(env, (char*) "Cannot read bitmap pixels");
    120         return;
    121     }
    122 
    123     // Unlock the pixels.
    124     result = AndroidBitmap_unlockPixels(env, jbitmap);
    125     if (result < 0) {
    126         throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
    127     }
    128 }
    129 
    130 static void writeBitmapPixels(JNIEnv* env, jclass clazz, jobject jbitmap, jint fd) {
    131     // Get the info.
    132     AndroidBitmapInfo info;
    133     int result = AndroidBitmap_getInfo(env, jbitmap, &info);
    134     if (result < 0) {
    135         throwIllegalStateException(env, (char*) "Cannot get bitmap info");
    136         return;
    137     }
    138 
    139     // Write the info.
    140     bool written = writeAllBytes(fd, (void*) &info, sizeof(AndroidBitmapInfo));
    141     if (!written) {
    142         throwIllegalStateException(env, (char*) "Cannot write bitmap info");
    143         return;
    144     }
    145 
    146     // Lock the pixels.
    147     void* pixels;
    148     result = AndroidBitmap_lockPixels(env, jbitmap, &pixels);
    149     if (result < 0) {
    150         throwIllegalStateException(env, (char*) "Cannot lock bitmap pixels");
    151         return;
    152     }
    153 
    154     // Write the pixels.
    155     size_t byteCount = info.stride * info.height;
    156     written = writeAllBytes(fd, (void*) pixels, byteCount);
    157     if (!written) {
    158         throwIllegalStateException(env, (char*) "Cannot write bitmap pixels");
    159         return;
    160     }
    161 
    162     // Unlock the pixels.
    163     result = AndroidBitmap_unlockPixels(env, jbitmap);
    164     if (result < 0) {
    165         throwIllegalStateException(env, (char*) "Cannot unlock bitmap pixels");
    166     }
    167 }
    168 
    169 static JNINativeMethod sMethods[] = {
    170     {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
    171     {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
    172 };
    173 
    174 int register_com_android_printspooler_util_BitmapSerializeUtils(JNIEnv* env) {
    175     return jniRegisterNativeMethods(env, "com/android/printspooler/util/BitmapSerializeUtils",
    176         sMethods, NELEM(sMethods));
    177 }
    178 
    179 }
    180 
    181 jint JNI_OnLoad(JavaVM* jvm, void*) {
    182     JNIEnv *env = NULL;
    183     if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6)) {
    184         return JNI_ERR;
    185     }
    186 
    187     if (android::register_com_android_printspooler_util_BitmapSerializeUtils(env) == -1) {
    188         return JNI_ERR;
    189     }
    190 
    191     return JNI_VERSION_1_6;
    192 }
    193