void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) { const int red = (background_rgb >> 16) & 0xff; const int green = (background_rgb >> 8) & 0xff; const int blue = (background_rgb >> 0) & 0xff; int x, y; if (pic == NULL) return; if (!pic->use_argb) { const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF); // VP8RGBToU/V expects the u/v values summed over four pixels const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF); const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT; if (!has_alpha || pic->a == NULL) return; // nothing to do for (y = 0; y < pic->height; ++y) { // Luma blending uint8_t* const y_ptr = pic->y + y * pic->y_stride; uint8_t* const a_ptr = pic->a + y * pic->a_stride; for (x = 0; x < pic->width; ++x) { const int alpha = a_ptr[x]; if (alpha < 0xff) { y_ptr[x] = BLEND(Y0, y_ptr[x], a_ptr[x]); } } // Chroma blending every even line if ((y & 1) == 0) { uint8_t* const u = pic->u + (y >> 1) * pic->uv_stride; uint8_t* const v = pic->v + (y >> 1) * pic->uv_stride; uint8_t* const a_ptr2 = (y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride; for (x = 0; x < uv_width; ++x) { // Average four alpha values into a single blending weight. // TODO(skal): might lead to visible contouring. Can we do better? const int alpha = a_ptr[2 * x + 0] + a_ptr[2 * x + 1] + a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1]; u[x] = BLEND_10BIT(U0, u[x], alpha); v[x] = BLEND_10BIT(V0, v[x], alpha); } if (pic->width & 1) { // rightmost pixel const int alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]); u[x] = BLEND_10BIT(U0, u[x], alpha); v[x] = BLEND_10BIT(V0, v[x], alpha); } } memset(a_ptr, 0xff, pic->width); } } else {
static void ConvertRGBA32ToUV_NEON(const uint16_t* rgb, uint8_t* u, uint8_t* v, int width) { int i; for (i = 0; i + 8 <= width; i += 8, rgb += 4 * 8) { const uint16x8x4_t RGB = vld4q_u16((const uint16_t*)rgb); int16x8_t U, V; CONVERT_RGB_TO_UV(RGB.val[0], RGB.val[1], RGB.val[2], 2, U, V); vst1_u8(u + i, vqrshrun_n_s16(U, 2)); vst1_u8(v + i, vqrshrun_n_s16(V, 2)); } for (; i < width; i += 1, rgb += 4) { const int r = rgb[0], g = rgb[1], b = rgb[2]; u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2); v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2); } }