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