如何在Android开发中使用JNI从Java传递位图到C++?

6

我希望在Android开发中使用JNI将位图从Android传递到C++。

在Java中,我调用此函数将Bitmap从Java发送到C++:

public native int sendMyBitmap(Bitmap bitmap);

在JNI中,我是这样做的:

JNIEXPORT void JNICALL sendMyBitmap(JNIEnv * env,
        jobject obj, jobject bitmap) 
{
    AndroidBitmapInfo androidBitmapInfo ;
    void* pixels;
    AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo);
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
    unsigned char* pixelsChar = (unsigned char*) pixels;
    saveImage(pixelsChar);
}

void saveImage(unsigned char* img)
{
    FILE *f;
    int w = 640, h = 480;

    int filesize = 54 + 3*w*h;  //w is your image width, h is image height, both int

    unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0};
    unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0};
    unsigned char bmppad[3] = {0,0,0};

    bmpfileheader[ 2] = (unsigned char)(filesize    );
    bmpfileheader[ 3] = (unsigned char)(filesize>> 8);
    bmpfileheader[ 4] = (unsigned char)(filesize>>16);
    bmpfileheader[ 5] = (unsigned char)(filesize>>24);

    bmpinfoheader[ 4] = (unsigned char)(       w    );
    bmpinfoheader[ 5] = (unsigned char)(       w>> 8);
    bmpinfoheader[ 6] = (unsigned char)(       w>>16);
    bmpinfoheader[ 7] = (unsigned char)(       w>>24);
    bmpinfoheader[ 8] = (unsigned char)(       h    );
    bmpinfoheader[ 9] = (unsigned char)(       h>> 8);
    bmpinfoheader[10] = (unsigned char)(       h>>16);
    bmpinfoheader[11] = (unsigned char)(       h>>24);

    f = fopen("/storage/test.png","wb");
    fwrite(bmpfileheader,1,14,f);
    fwrite(bmpinfoheader,1,40,f);
    for(int i=0; i<h; i++)
    {
        fwrite(img+(w*(h-i-1)*3),3,w,f);
        fwrite(bmppad,1,(4-(w*3)%4)%4,f);
    }
    fflush(f);
    fclose(f);
}

在C++ JNI中保存位图后,Java中的位图和C++中的位图是不同的。我在努力找出问题出在哪里以及如何解决它。


请描述预期结果与实际结果。 - krsteeve
1个回答

3

这行:

fwrite(img + (w * (h - i - 1)*3), 3, w, f);

您假设输入的位图每个像素有24位(3字节)。但是在Android中没有这样的像素格式。
您还假设宽度正好为640像素,高度正好为480像素。虽然在您的情况下可能是真的,但您应该读取此信息,而不是硬编码值。
所有这些值都由函数AndroidBitmap_getInfo()提供。为什么不使用它们呢?只需检查结构体AndroidBitmapInfo:
typedef struct {
    uint32_t    width;
    uint32_t    height;
    uint32_t    stride;
    int32_t     format;
    uint32_t    flags;      // 0 for now
} AndroidBitmapInfo;

您可以直接读取位图的尺寸。此外,您应该检查参数format,它可以是以下值之一:

enum AndroidBitmapFormat {
    ANDROID_BITMAP_FORMAT_NONE      = 0,
    ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
    ANDROID_BITMAP_FORMAT_RGB_565   = 4,
    ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
    ANDROID_BITMAP_FORMAT_A_8       = 8,
};

你看到了吗?没有RGB_888格式。你应该确保从Java到C++发送的位图以RGBA_8888像素格式发送,并相应地修改算法。我认为将输出像素格式更改为32位(而不是24位)会更容易。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接