/** \file * \brief Image Resource. * * See Copyright Notice in "iup.h" */ #include #include #include #include #include "iup.h" #include "iup_object.h" #include "iup_attrib.h" #include "iup_str.h" #include "iup_image.h" #include "iupandroid_drv.h" #include // link to jnigraphics #include #include #include "iupandroid_jnimacros.h" #include "iupandroid_jnicacheglobals.h" IUPJNI_DECLARE_CLASS_STATIC(IupImageHelper); IUPJNI_DECLARE_METHOD_ID_STATIC(IupImageHelper_createBitmap); /* Adapted from SDL (zlib) * Calculate the pad-aligned scanline width of a surface */ static int CalculateBytesPerRow(int width, int bytes_per_pixel) { int pitch; int bits_per_pixel = bytes_per_pixel * 8; /* Surface should be 4-byte aligned for speed */ pitch = width * bytes_per_pixel; switch (bits_per_pixel) { case 1: pitch = (pitch + 7) / 8; break; case 4: pitch = (pitch + 1) / 2; break; default: break; } pitch = (pitch + 3) & ~3; /* 4-byte aligning */ return (pitch); } static int CalculateRowLength(int width, int bytes_per_pixel) { int pitch = CalculateBytesPerRow(width, bytes_per_pixel); return pitch/bytes_per_pixel; } // FIXME: Carried over implementation. Probably wrong. Untested, don't know what calls this, don't know how to test. void iupdrvImageGetRawData(void* handle, unsigned char* imgdata) { #if 0 int x,y; unsigned char *red,*green,*blue,*alpha; NSImage *image = (__bridge NSImage*)handle; NSBitmapImageRep *bitmap = nil; if([[image representations] count]>0) bitmap = [[image representations] objectAtIndex:0]; if(bitmap==nil) return; NSInteger w = [bitmap pixelsWide]; NSInteger h = [bitmap pixelsHigh]; NSInteger bpp = [bitmap bitsPerPixel]; NSInteger planesize = w*h; unsigned char *bits = [bitmap bitmapData]; red = imgdata; green = imgdata+planesize; blue = imgdata+2*planesize; alpha = imgdata+3*planesize; for(y=0;y=24) { *red++ = *bits++; *green++ = *bits++; *blue++ = *bits++; } if(bpp==32) { *alpha++ = *bits++; } } } #endif } // FIXME: Carried over implementation. Probably wrong. Untested, don't know what calls this, don't know how to test. void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata) { JNIEnv* jni_env = iupAndroid_GetEnvThreadSafe(); jmethodID method_id = NULL; jobject java_bitmap = NULL; int ret_val; AndroidBitmapInfo bitmap_info; jclass java_class = IUPJNI_FindClass(IupImageHelper, jni_env, "br/pucrio/tecgraf/iup/IupImageHelper"); method_id = IUPJNI_GetStaticMethodID(IupImageHelper_createBitmap, jni_env, java_class, "createBitmap", "(III)Landroid.graphics.Bitmap;"); if(32 == bpp) { unsigned char* pixels; unsigned char* source_pixel = imgdata; // Note that the Android format is ARGB // createBitmap() java_bitmap = (*jni_env)->CallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // Technically we are iterating through the source image, not the target image, so using bitmap_info.stride feels wrong. // int row_length = bitmap_info.stride/(32/8); int row_length = CalculateRowLength(width, 4); for(int y=0;yCallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // Technically we are iterating through the source image, not the target image, so using bitmap_info.stride feels wrong. // int row_length = bitmap_info.stride/(24/8); int row_length = CalculateRowLength(width, 3); for(int y=0;yCallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // int row_length = bitmap_info.stride/(32/8); int row_length = CalculateRowLength(width, 4); int colors_count = 0; iupColor colors[256]; for(int y=0;yr; unsigned char s_g = c->g; unsigned char s_b = c->b; unsigned char s_a; if(has_alpha) { s_a = c->a; } else { s_a = 255; } // Even though the declared format is ARGB, experimentally setting this array, the order seems to be RGBA. *pixels = s_r; pixels++; *pixels = s_g; pixels++; *pixels = s_b; pixels++; *pixels = s_a; pixels++; source_pixel++; } } AndroidBitmap_unlockPixels(jni_env, java_bitmap); } CLEANUP: (*jni_env)->DeleteLocalRef(jni_env, java_class); if(NULL != java_bitmap) { jobject return_bitmap = (*jni_env)->NewGlobalRef(jni_env, java_bitmap); (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); return return_bitmap; } else { return NULL; } } int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count) { /* How to get the pallete? */ (void)colors; (void)colors_count; return iupdrvImageGetInfo(handle, w, h, bpp); } // NOTE: Returns an autoreleased NSImage. void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive) { JNIEnv* jni_env = iupAndroid_GetEnvThreadSafe(); jmethodID method_id = NULL; jobject java_bitmap = NULL; int ret_val; AndroidBitmapInfo bitmap_info; int bpp; int width; int height; unsigned char* imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); width = ih->currentwidth; height = ih->currentheight; bpp = iupAttribGetInt(ih, "BPP"); unsigned char bg_r=0, bg_g=0, bg_b=0; iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b); jclass java_class = IUPJNI_FindClass(IupImageHelper, jni_env, "br/pucrio/tecgraf/iup/IupImageHelper"); method_id = IUPJNI_GetStaticMethodID(IupImageHelper_createBitmap, jni_env, java_class, "createBitmap", "(III)Landroid/graphics/Bitmap;"); if(32 == bpp) { unsigned char* pixels; unsigned char* source_pixel = imgdata; // Note that the Android format is ARGB // createBitmap() java_bitmap = (*jni_env)->CallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // void* start_pixels = NULL; ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); // ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, &start_pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // pixels = (unsigned char*)start_pixels; // Technically we are iterating through the source image, not the target image, so using bitmap_info.stride feels wrong. // int row_length = bitmap_info.stride/(32/8); int row_length = CalculateRowLength(width, 4); for(int y=0;yCallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // Technically we are iterating through the source image, not the target image, so using bitmap_info.stride feels wrong. // int row_length = bitmap_info.stride/(24/8); int row_length = CalculateRowLength(width, 3); for(int y=0;yCallStaticObjectMethod(jni_env, java_class, method_id, (jint)width, (jint)height, (jint)32 ); if(NULL == java_bitmap) { goto CLEANUP; } ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } ret_val = AndroidBitmap_lockPixels(jni_env, java_bitmap, (void**)&pixels); if(ret_val < 0) { (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); java_bitmap = NULL; __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); goto CLEANUP; } // int row_length = bitmap_info.stride/(32/8); int row_length = CalculateRowLength(width, 4); int colors_count = 0; iupColor colors[256]; int has_alpha = iupImageInitColorTable(ih, colors, &colors_count); for(int y=0;yr; unsigned char s_g = c->g; unsigned char s_b = c->b; unsigned char s_a; if(has_alpha) { s_a = c->a; } else { s_a = 255; } if(make_inactive) { iupImageColorMakeInactive(&s_r, &s_g, &s_b, bg_r, bg_g, bg_b); } // Even though the declared format is ARGB, experimentally setting this array, the order seems to be RGBA. *pixels = s_r; pixels++; *pixels = s_g; pixels++; *pixels = s_b; pixels++; *pixels = s_a; pixels++; source_pixel++; } } AndroidBitmap_unlockPixels(jni_env, java_bitmap); } int bgcolor_depend = 0; if(bgcolor_depend || make_inactive) { iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1"); } CLEANUP: (*jni_env)->DeleteLocalRef(jni_env, java_class); if(NULL != java_bitmap) { jobject return_bitmap = (*jni_env)->NewGlobalRef(jni_env, java_bitmap); (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); return return_bitmap; } else { return NULL; } } void* iupdrvImageCreateIcon(Ihandle *ih) { return iupdrvImageCreateImage(ih, NULL, 0); } void* iupdrvImageCreateCursor(Ihandle *ih) { #if 0 int bpp,y,x,hx,hy, width = ih->currentwidth, height = ih->currentheight, line_size = (width+7)/8, size_bytes = line_size*height; unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); char *sbits, *mbits, *sb, *mb; unsigned char r, g, b; bpp = iupAttribGetInt(ih, "BPP"); if (bpp > 8) return NULL; sbits = (char*)malloc(2*size_bytes); if (!sbits) return NULL; memset(sbits, 0, 2*size_bytes); mbits = sbits + size_bytes; sb = sbits; mb = mbits; for (y=0; ycurrentwidth, height = ih->currentheight, line_size = (width+7)/8, size_bytes = line_size*height; unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); char *bits, *sb; unsigned char colors[256]; bpp = iupAttribGetInt(ih, "BPP"); if (bpp > 8) return NULL; bits = (char*)malloc(size_bytes); if (!bits) return NULL; memset(bits, 0, size_bytes); iupImageInitNonBgColors(ih, colors); sb = bits; for (y=0; yNewStringUTF(jni_env, name); java_bitmap = (*jni_env)->CallStaticObjectMethod(jni_env, java_class, method_id, j_string ); (*jni_env)->DeleteLocalRef(jni_env, j_string); (*jni_env)->DeleteLocalRef(jni_env, java_class); if(NULL != java_bitmap) { jobject return_bitmap = (*jni_env)->NewGlobalRef(jni_env, java_bitmap); (*jni_env)->DeleteLocalRef(jni_env, java_bitmap); return return_bitmap; } else { return NULL; } } int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp) { jobject java_bitmap = (jobject)handle; if(NULL == java_bitmap) { return 0; } JNIEnv* jni_env = iupAndroid_GetEnvThreadSafe(); int ret_val; AndroidBitmapInfo bitmap_info; ret_val = AndroidBitmap_getInfo(jni_env, java_bitmap, &bitmap_info); if(ret_val < 0) { __android_log_print(ANDROID_LOG_ERROR, "iupandroid_image", "AndroidBitmap_getInfo() failed:%d", ret_val); return 0; } if(w) *w = bitmap_info.width; if(h) *h = bitmap_info.height; // We only can use ARGB_8888 for all formats, this is always going to be 32 if(bpp) *bpp = 32; return 1; } // [NSApp setApplicationIconImage: [NSImage imageNamed: @"Icon_name.icns"]] void iupdrvImageDestroy(void* handle, int type) { if(NULL == handle) { return; } JNIEnv* jni_env = iupAndroid_GetEnvThreadSafe(); (*jni_env)->DeleteGlobalRef(jni_env, (jobject)handle); } void iupdrvImageGetData(void* handle, unsigned char* imgdata) { }