encode bitmap to webp with libwebp on Android pre

2019-09-08 06:16发布

问题:

I want to encode Bitmap to webp on Android 2.x device with libwebp. Below is my testing code

public static int createWebPImage(Bitmap bitmap, String outFilePath) {
    Log.d(TAG, "create webp image");
    ByteBuffer buffer = ByteBuffer.allocateDirect(BitmapCompat.getAllocationByteCount(bitmap));
    bitmap.copyPixelsToBuffer(buffer);
    return nativeCreateWebPImage(buffer, bitmap.getWidth(), bitmap.getHeight(), outFilePath);
}

And the jni implementation is

nativeCreateWebPImage(JNIEnv *env, jclass type, jobject directBuffer, jint width, jint height, jstring outFilePath_) {
    const char *outFilePath = env->GetStringUTFChars(outFilePath_, 0);
    int ret = 0;
    FILE* file = NULL;
    if ((file = fopen(outFilePath, "w+")) != NULL) {
        uint8_t* buffer = (uint8_t *) env->GetDirectBufferAddress(directBuffer);
        LOGD("size of the bitmap %lu", (unsigned long) env->GetDirectBufferCapacity(directBuffer));
        uint8_t* output = (uint8_t *) malloc((size_t) env->GetDirectBufferCapacity(directBuffer));
        size_t n = WebPEncodeRGBA(buffer, width, height, width, 0.9, &output);
        if (n <= 0) {
            LOGD("webp encode failed");
            ret = -1;
        } else {
            LOGD("write to file");
            if (fwrite(output, sizeof(uint8_t), n, file) != n) {
                LOGD("write file error");
                ret = -1;
            }
        }

        free(output);
        fclose(file);
    } else {
        LOGD("open file error %s", outFilePath);
        ret = -1;
    }
    env->ReleaseStringUTFChars(outFilePath_, outFilePath);
    return ret;
}

The resulting file was created successfully, but the encoded image was totally broken. The image seems filled with the wrong data. Is the parameters wrong when calling WebPEncodeRGBA? The bitmap configuration is Bitmap.Config.ARGB_8888.

How can I correctly encode Bitmap to webp with the API call WebPEncodeRGBA?

回答1:

After read the docs from Google, I found the stride parameter was wrong. It should be counted as bytes. Then I changed the encode function call to

WebPEncodeRGBA(buffer, width, height, width * 4 /* stride in bytes */, 0.9, &output);

It worked.