You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android JNI原生C++修改Bitmap红通道像素值异常求助

问题根因排查

    1. 通道字节顺序错误
      Android的ANDROID_BITMAP_FORMAT_RGBA_8888格式的像素在native内存中为小端存储,32位无符号整数的位分配为:
    • 0~7位:蓝色通道(B)
    • 8~15位:绿色通道(G)
    • 16~23位:红色通道(R)
    • 24~31位:透明度通道(A)
      你原代码把红色值写入0~7位,相当于给蓝色通道赋值255,所以最终输出全蓝色图像,同时未对Alpha通道赋值,导致透明度异常,出现全透明/全白的问题。
    1. 新Bitmap宽高传参错误
      调用createBitmap时你把原Bitmap的height作为宽度、width作为高度传入,导致新画布尺寸不对。
    1. 像素翻转逻辑无必要且错误
      你未说明需要翻转图像,原有的逆向x轴遍历逻辑会导致图像横向翻转,不符合常规需求。

修复后完整实现代码

#include <android/bitmap.h>
#include <algorithm> // 用于通道值溢出保护

jobject Java_com_journaldev_androidjnibasics_MainActivity_sendMyBitmap(JNIEnv *env, jobject thiz, jobject bitmap) {
    AndroidBitmapInfo info;
    int ret;
    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        return NULL;
    }
    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        return NULL;
    }

    void *bitmapPixels;
    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) {
        return NULL;
    }
    uint32_t *src = (uint32_t *) bitmapPixels;
    int pixelsCount = info.height * info.width;
    uint32_t *tempPixels = new uint32_t[pixelsCount];

    for (int y=0; y<info.height; y++) {
        uint32_t * line = (uint32_t *)bitmapPixels;
        for (int x=0; x<info.width; x++) {
            // 修正通道读取顺序
            uint8_t blue = (uint8_t) (line[x] & 0x000000FF);
            uint8_t green = (uint8_t)((line[x] & 0x0000FF00) >> 8);
            uint8_t red = (uint8_t) ((line[x] & 0x00FF0000) >> 16);
            uint8_t alpha = (uint8_t) ((line[x] & 0xFF000000) >> 24);

            // 测试:全红设置,若要实现红色通道提升可替换为 red = std::min(255, red + 偏移值);
            red = 255;
            green = 0;
            blue = 0;
            alpha = 255; // 明确设置为不透明,避免透明异常

            // 修正通道写入顺序
            line[x] = (alpha << 24) | (red << 16) | (green << 8) | blue;
        }
        bitmapPixels = (char *)bitmapPixels + info.stride;
    }

    memcpy(tempPixels, src, sizeof(uint32_t) * pixelsCount);
    AndroidBitmap_unlockPixels(env, bitmap);

    // 回收原Bitmap
    jclass bitmapCls = env->GetObjectClass(bitmap);
    jmethodID recycleFunction = env->GetMethodID(bitmapCls, "recycle", "()V");
    if (recycleFunction == 0) {
        delete[] tempPixels;
        return NULL;
    }
    env->CallVoidMethod(bitmap, recycleFunction);

    // 修正新Bitmap宽高传参顺序
    jmethodID createBitmapFunction = env->GetStaticMethodID(bitmapCls, "createBitmap",
                                                            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
    jstring configName = env->NewStringUTF("ARGB_8888");
    jclass bitmapConfigClass = env->FindClass("android/graphics/Bitmap$Config");
    jmethodID valueOfBitmapConfigFunction = env->GetStaticMethodID(bitmapConfigClass, "valueOf",
                                                                   "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
    jobject bitmapConfig = env->CallStaticObjectMethod(bitmapConfigClass, valueOfBitmapConfigFunction, configName);
    jobject newBitmap = env->CallStaticObjectMethod(bitmapCls, createBitmapFunction, info.width, info.height, bitmapConfig);

    // 写入新Bitmap,移除不必要的翻转逻辑,直接拷贝即可
    if ((ret = AndroidBitmap_lockPixels(env, newBitmap, &bitmapPixels)) < 0) {
        delete[] tempPixels;
        return NULL;
    }
    uint32_t *newBitmapPixels = (uint32_t *) bitmapPixels;
    memcpy(newBitmapPixels, tempPixels, sizeof(uint32_t) * pixelsCount);
    AndroidBitmap_unlockPixels(env, newBitmap);

    delete[] tempPixels;
    return newBitmap;
}

内容的提问来源于stack exchange,提问作者mariya sebastian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 16:54:01