jboolean decodeRGBAIntoInternal(JNIEnv * env, AndroidBitmapInfo info, jbyteArray encoded, jobject bitmap) {
size_t output_buffer_size;
uint8_t* result;
void *pixels;
int ret;
jbyte* encoded_array;
jsize encoded_length;
int width = 0;
int height = 0;
output_buffer_size = info.height * info.stride;
encoded_array = (*env)->GetByteArrayElements(env, encoded, NULL);
encoded_length = (*env)->GetArrayLength(env, encoded);
ret = WebPGetInfo(encoded_array, encoded_length, &width, &height);
if (!ret) {
LOGE("unable to get webp info");
return JNI_FALSE;
}
if (info.width != width || info.height != height) {
LOGE("webp size %dx%d does not match bitmap size %dx%d", width, height, info.width, info.height);
return JNI_FALSE;
}
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
return JNI_FALSE;
}
result = WebPDecodeRGBAInto(encoded_array, encoded_length, (uint8_t*) pixels, output_buffer_size, info.stride);
AndroidBitmap_unlockPixels(env, bitmap);
(*env)->ReleaseByteArrayElements(env, encoded, encoded_array, JNI_ABORT);
return result ? JNI_TRUE : JNI_FALSE;
}
Hi everyone,Romain Guy wrote that Android expects the Bitmap data to be in pre-multiplied form:From then on I found out the webp library has a MODE_rgbA. So I quickly tried to create a WebPDecodergbAInto method (notice the small 'rgb' letters) that uses this mode MODE_rgbA instead of MODE_RGBA, and seems to apply the pre-multiplication.This seems to solve my test case with the single pixel. But more complex examples, like 'testLine' or 'testComplexRoundImage' still fail. 'testLine':Pixels at (5, 0) have different colors. expected:<#870[202]00> but was:<#870[000]00>
So there seems to be something else I have to do. Any ideas?And does anyone know if there is a method to access the static function DecodeIntoRGBABuffer externally? Because otherwise I will have to copy the whole webp library into my Github project…
--
You received this message because you are subscribed to the Google Groups "WebP Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to webp-discuss...@webmproject.org.
To post to this group, send email to webp-d...@webmproject.org.
Visit this group at https://groups.google.com/a/webmproject.org/group/webp-discuss/.
For more options, visit https://groups.google.com/a/webmproject.org/d/optout.
how did you generate the reference PNG image that you are comparing to in the unit-test?
The same pre-multiplication formula as libwebp must be used.In libwebp, we use: x = (int)(X * alpha / 255.) to pre-multiply.
static inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) {
SkASSERT(a <= 32767);
SkASSERT(b <= 32767);
unsigned prod = a*b + 128;
return (prod + (prod >> 8)) >> 8;
}
static inline
SkPMColor SkPremultiplyARGBInline(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
if (a != 255) {
r = SkMulDiv255Round(r, a);
g = SkMulDiv255Round(g, a);
b = SkMulDiv255Round(b, a);
}
return SkPackARGB32(a, r, g, b);
}
So there seems to be something else I have to do. Any ideas?And does anyone know if there is a method to access the static function DecodeIntoRGBABuffer externally? Because otherwise I will have to copy the whole webp library into my Github project…Hmm... this function is only a helper function for the visible public ones (WebPDecodeXXXInto).Even if we could make it public (maybe we need a WebPDecodergbAInto variant after all), this wouldn't be backward compatiblewith older libwebp libraries shipped on Android < 0.4.3... (if you're using them). Your best shot would be using the advanced decodingAPI (which pretty much amounts to re-rewriting DecodeIntoRGBABuffer()'s code, but this API isn't mapped in the JNI yet.
- Contribute to the WebP implementation to use the Android pre-multiplication formula - though I don't know if this is the right way to go, because it could break results for existing users of the rgbA variants. Or maybe it wouldn't break - at least these variants are private up until now and don't seem to be used, so it would be an internal change.
I think I will try out option (2) - but maybe you guys are interested in option (3)?
So there seems to be something else I have to do. Any ideas?And does anyone know if there is a method to access the static function DecodeIntoRGBABuffer externally? Because otherwise I will have to copy the whole webp library into my Github project…Hmm... this function is only a helper function for the visible public ones (WebPDecodeXXXInto).Even if we could make it public (maybe we need a WebPDecodergbAInto variant after all), this wouldn't be backward compatiblewith older libwebp libraries shipped on Android < 0.4.3... (if you're using them). Your best shot would be using the advanced decodingAPI (which pretty much amounts to re-rewriting DecodeIntoRGBABuffer()'s code, but this API isn't mapped in the JNI yet.I am not using the old WebP libs anyway because the whole point of my WebP backport library is to bring the features of the new WebP versions to older versions of Android. Including decoding images with alpha channel on Android versions down to 2.3. :)
I am not using the SWIG bindings in my current version of webp-backport. I started to use them in the beginning, but got native crashes pretty quick. I didn't try them out much more, and found a way to use just the functions I need and write the needed JNI bindings myself. Which might not be such a good idea at a second look - but for now it seems to work. :)I can't say how thankful I am for your help - thanks a lot! And if we meet in real life I'd like to invite you to a beer! :)
#include <stdio.h>
int main() {
for (unsigned b = 0; b < 256; ++b) {
for (unsigned a = 0; a < 256; ++a) {
const unsigned prod = a * b + 128;
const unsigned v0 = (prod + (prod >> 8)) >> 8;
const unsigned v1 = (int)(a * b / 255. + .5);
const unsigned v2 = (b * a * 65793 + (1 << 23)) >> 24;
if (v0 != v1 || v0 != v2) {
printf("!! a=%d b=%d -> v= %d / %d / %d\n", a, b, v0, v1, v2);
return -1;
}
}
}
printf("OK!\n");
return 0;
}
At some point, i think i experimented with a similar formula than Skia. But then reverted to the one we have now, because it's easier and faster to implement (esp. in SSE2).But! the code still has a trace Skia's variant[*]. In alpha_processing.c:210 for instance, you have the comment:// ... For bit-wise equivalence to (int)(x * a / 255. + .5),
// one can use instead: (x * a * 65793 + (1 << 23)) >> 24So, if you have WebP's code around, you can simply modify the "#if 1" a line alpha_processing.c:212 to get Skia's behaviour.SSE2 variant should be straightforward to adapt, but as I said, there's an extra add, which makes it slightly slower for a minordiff in precision.
Thanks a lot for doing this! This is quite useful.