在 Java 上创建位图并使用 JNI 将其发送到 C++ 并通过 OpenGL 渲染它,黑色
Create bitmap on Java and send it to C++ using JNI and render it by OpenGL, black
在 Android 上,我使用 JNI 将字符串从 C++ 发送到 Java,然后将其绘制到位图,然后 return 将字节数组返回到 C++ 以将其绘制到 OpenGL ,我得到一个黑色矩形。
首先,我通过这种方式在 Java 中创建位图:
public static byte[] DrawString(String text) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(110, 110, 110));
float scale = ActivityGame.getCurrentActivity().getResources().getDisplayMetrics().density;
paint.setTextSize((int) (24 * scale));
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Bitmap bitmap = Bitmap.createBitmap((int) (bounds.width() * scale), (int) (bounds.height() * scale), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int x = (bitmap.getWidth() - bounds.width()) / 6;
int y = (bitmap.getHeight() + bounds.height()) / 5;
canvas.drawText(text, x * scale, y * scale, paint);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
return byteArray;
}
然后在C++中我通过JNI这样调用前面的函数:
static unsigned char* DrawString(std::string text,int* length){
JNIEnv *env= nullptr;
JNIUtils::JVM->AttachCurrentThread(&env, NULL);
jclass jniUtilsCls = env->FindClass("com/moussa/mightypolygons/JNIUtils");
jmethodID drawStringMethodId = env->GetStaticMethodID(jniUtilsCls, "DrawString", "(Ljava/lang/String;)[B");
jstring _text=env->NewStringUTF(text.c_str());
jbyteArray bmpArr=(jbyteArray)env->CallStaticObjectMethod(jniUtilsCls,drawStringMethodId,_text);
jsize num_bytes = env->GetArrayLength( bmpArr);
jbyte* elements = env->GetByteArrayElements(bmpArr, NULL);
unsigned char* bmp=new unsigned char[num_bytes];
if (elements) {
for(int i = 0; i < num_bytes; i++) {
bmp[i] = elements[i];
}
*length=(int)num_bytes;
return bmp;
}
return NULL;
}
我终于得到了字符数组和长度,现在我在 OpenGL 中创建了一个纹理:
Texture::Texture(unsigned char *bmp,int len, TextureTypes type) {
image = stbi_load_from_memory(bmp,len, &width, &height, &nrComponents, 4);
glGenTextures(1, &textureObj);
if (image) {
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
else
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureObj);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(image);
} else {
stbi_image_free(image);
}
}
我得到一个与位图宽度和高度相同的黑色矩形。
编辑:
我从 Java 端将位图保存为 PNG,然后从 C++ 重新加载它,它使用相同的代码完美呈现,所以问题出在字节数组或 GL 参数或其他方面吗?
编辑 2:
我在 Java 中注意到 ByteArray
包含带负值的带符号字节,当它在 C++ 中转换为 unsigned char*
时它的值发生了变化,例如字节数组中的第一个字节在 Java 中是 -119 如果转换为 unsigned char
则变为 137
我使用不同的方法发送来自 Java 的位图对象,并使用 android/bitmap.h
读取其像素
AndroidBitmapInfo androidBitmapInfo ;
void* pixels;
AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
unsigned char* pixelsChar = (unsigned char*) pixels;
AndroidBitmap_unlockPixels(env, bitmap);
现在可以正常使用了。
在 Android 上,我使用 JNI 将字符串从 C++ 发送到 Java,然后将其绘制到位图,然后 return 将字节数组返回到 C++ 以将其绘制到 OpenGL ,我得到一个黑色矩形。
首先,我通过这种方式在 Java 中创建位图:
public static byte[] DrawString(String text) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(110, 110, 110));
float scale = ActivityGame.getCurrentActivity().getResources().getDisplayMetrics().density;
paint.setTextSize((int) (24 * scale));
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
Bitmap bitmap = Bitmap.createBitmap((int) (bounds.width() * scale), (int) (bounds.height() * scale), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int x = (bitmap.getWidth() - bounds.width()) / 6;
int y = (bitmap.getHeight() + bounds.height()) / 5;
canvas.drawText(text, x * scale, y * scale, paint);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
return byteArray;
}
然后在C++中我通过JNI这样调用前面的函数:
static unsigned char* DrawString(std::string text,int* length){
JNIEnv *env= nullptr;
JNIUtils::JVM->AttachCurrentThread(&env, NULL);
jclass jniUtilsCls = env->FindClass("com/moussa/mightypolygons/JNIUtils");
jmethodID drawStringMethodId = env->GetStaticMethodID(jniUtilsCls, "DrawString", "(Ljava/lang/String;)[B");
jstring _text=env->NewStringUTF(text.c_str());
jbyteArray bmpArr=(jbyteArray)env->CallStaticObjectMethod(jniUtilsCls,drawStringMethodId,_text);
jsize num_bytes = env->GetArrayLength( bmpArr);
jbyte* elements = env->GetByteArrayElements(bmpArr, NULL);
unsigned char* bmp=new unsigned char[num_bytes];
if (elements) {
for(int i = 0; i < num_bytes; i++) {
bmp[i] = elements[i];
}
*length=(int)num_bytes;
return bmp;
}
return NULL;
}
我终于得到了字符数组和长度,现在我在 OpenGL 中创建了一个纹理:
Texture::Texture(unsigned char *bmp,int len, TextureTypes type) {
image = stbi_load_from_memory(bmp,len, &width, &height, &nrComponents, 4);
glGenTextures(1, &textureObj);
if (image) {
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
else
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureObj);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(image);
} else {
stbi_image_free(image);
}
}
我得到一个与位图宽度和高度相同的黑色矩形。
编辑:
我从 Java 端将位图保存为 PNG,然后从 C++ 重新加载它,它使用相同的代码完美呈现,所以问题出在字节数组或 GL 参数或其他方面吗?
编辑 2:
我在 Java 中注意到 ByteArray
包含带负值的带符号字节,当它在 C++ 中转换为 unsigned char*
时它的值发生了变化,例如字节数组中的第一个字节在 Java 中是 -119 如果转换为 unsigned char
我使用不同的方法发送来自 Java 的位图对象,并使用 android/bitmap.h
AndroidBitmapInfo androidBitmapInfo ;
void* pixels;
AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
unsigned char* pixelsChar = (unsigned char*) pixels;
AndroidBitmap_unlockPixels(env, bitmap);
现在可以正常使用了。