Chromium Code Reviews| Index: Source/platform/image-encoders/skia/WEBPImageEncoder.cpp |
| diff --git a/Source/platform/image-encoders/skia/WEBPImageEncoder.cpp b/Source/platform/image-encoders/skia/WEBPImageEncoder.cpp |
| index 5edcf10eee691e45c13728479856d42547163155..6aaf38fdfb5c5780d35598abb1d9cb2811c6004a 100644 |
| --- a/Source/platform/image-encoders/skia/WEBPImageEncoder.cpp |
| +++ b/Source/platform/image-encoders/skia/WEBPImageEncoder.cpp |
| @@ -46,54 +46,55 @@ static int writeOutput(const uint8_t* data, size_t size, const WebPPicture* cons |
| return 1; |
| } |
| -static bool rgbPictureImport(const unsigned char* pixels, bool premultiplied, WebPImporter importRGBX, WebPImporter importRGB, WebPPicture* picture) |
| +static bool rgbaPictureImport(const unsigned char* pixels, bool premultiplied, WebPImporter importRGBA, WebPPicture* picture) |
| { |
| - if (premultiplied) |
| - return importRGBX(picture, pixels, picture->width * 4); |
| + if (!premultiplied) |
| + return importRGBA(picture, pixels, picture->width * 4); |
| - // Write the RGB pixels to an rgb data buffer, alpha premultiplied, then import the rgb data. |
| + static const SkUnPreMultiply::Scale* scale = SkUnPreMultiply::GetScaleTable(); |
| size_t pixelCount = picture->height * picture->width; |
| - |
| - OwnPtr<unsigned char[]> rgb = adoptArrayPtr(new unsigned char[pixelCount * 3]); |
| - if (!rgb.get()) |
| + OwnPtr<unsigned char[]> rgba = adoptArrayPtr(new unsigned char[pixelCount * 4]); |
| + if (!rgba.get()) |
| return false; |
| - for (unsigned char* data = rgb.get(); pixelCount-- > 0; pixels += 4) { |
| + for (unsigned char* data = rgba.get(); pixelCount-- > 0; pixels += 4) { |
| unsigned char alpha = pixels[3]; |
| - if (alpha != 255) { |
| - *data++ = SkMulDiv255Round(pixels[0], alpha); |
| - *data++ = SkMulDiv255Round(pixels[1], alpha); |
| - *data++ = SkMulDiv255Round(pixels[2], alpha); |
| + if ((alpha != 0) && (alpha != 255)) { |
| + *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[0]); |
| + *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[1]); |
| + *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[2]); |
| + *data++ = alpha; |
| } else { |
| *data++ = pixels[0]; |
| *data++ = pixels[1]; |
| *data++ = pixels[2]; |
| + *data++ = alpha; |
| } |
| } |
| - return importRGB(picture, rgb.get(), picture->width * 3); |
| + return importRGBA(picture, rgba.get(), picture->width * 4); |
| } |
| -template <bool Premultiplied> inline bool importPictureBGRX(const unsigned char* pixels, WebPPicture* picture) |
| +template <bool Premultiplied> inline bool importPictureBGRA(const unsigned char* pixels, WebPPicture* picture) |
| { |
| - return rgbPictureImport(pixels, Premultiplied, &WebPPictureImportBGRX, &WebPPictureImportBGR, picture); |
| + return rgbaPictureImport(pixels, Premultiplied, &WebPPictureImportBGRA, picture); |
| } |
| -template <bool Premultiplied> inline bool importPictureRGBX(const unsigned char* pixels, WebPPicture* picture) |
| +template <bool Premultiplied> inline bool importPictureRGBA(const unsigned char* pixels, WebPPicture* picture) |
| { |
| - return rgbPictureImport(pixels, Premultiplied, &WebPPictureImportRGBX, &WebPPictureImportRGB, picture); |
| + return rgbaPictureImport(pixels, Premultiplied, &WebPPictureImportRGBA, picture); |
| } |
| static bool platformPremultipliedImportPicture(const unsigned char* pixels, WebPPicture* picture) |
| { |
| if (SK_B32_SHIFT) // Android |
| - return importPictureRGBX<true>(pixels, picture); |
| + return importPictureRGBA<true>(pixels, picture); |
| - return importPictureBGRX<true>(pixels, picture); |
| + return importPictureBGRA<true>(pixels, picture); |
| } |
| -static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool premultiplied, int quality, Vector<unsigned char>* output) |
| +static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool premultiplied, int quality, Vector<unsigned char>* output, WEBPImageEncoder::Mode mode) |
| { |
| if (imageSize.width() <= 0 || imageSize.width() > WEBP_MAX_DIMENSION) |
| return false; |
| @@ -109,38 +110,61 @@ static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool pr |
| picture.width = imageSize.width(); |
| picture.height = imageSize.height(); |
| + if (quality > 99 || mode == WEBPImageEncoder::Lossless) |
| + picture.use_argb = 1; |
|
acterhd
2015/08/27 17:18:19
I'm used backward compatibility with lossy without
|
| if (premultiplied && !platformPremultipliedImportPicture(pixels, &picture)) |
| return false; |
| - if (!premultiplied && !importPictureRGBX<false>(pixels, &picture)) |
| + if (!premultiplied && !importPictureRGBA<false>(pixels, &picture)) |
| return false; |
| picture.custom_ptr = output; |
| picture.writer = &writeOutput; |
| - config.quality = quality; |
| - config.method = 3; |
| + |
| + if (mode == WEBPImageEncoder::Lossless) { |
| + // libeweb > 0x0202 has a lossless preset http://bit.ly/1Pz9IkE |
| + // api, but it is not in chrome yet. Approximate it. |
| + ASSERT(quality >= 0 && quality <= 100); |
| + config.quality = quality; |
| + config.method = (quality * 6) / 100; |
|
urvang
2015/08/27 17:18:23
Large method values are pretty impractical: e.g. q
|
| + config.lossless = 1; |
| + } else if (quality > 99) { |
|
acterhd
2015/08/27 17:18:19
Bad idea, particularly for video (WebM) encoders w
|
| + // Use a middle-of-the-road quality, lossless webp encoding |
| + // -- to balance speed with compresssion time |
| + // -- to maintain sharpness (for text, see JPEG 4:4:4). |
| + // FIXME: should we use WebPPictureSmartARGBToYUVA() instead |
| + // for this case? Maybe compare it with the approach here in |
| + // terms of encoding speed and quality. |
|
Noel Gordon
2015/08/26 23:13:49
_and_ filesize.
|
| + config.quality = 75; |
|
Noel Gordon
2015/08/26 23:52:03
FIXME: use WEBPImageEncoder::DefaultCompressionQua
|
| + config.method = 4; |
| + config.lossless = 1; |
|
urvang
2015/08/27 17:18:23
We have a separate setting for lossless, so qualit
|
| + } else { |
| + config.quality = quality; |
| + config.method = 3; |
| + config.lossless = 0; |
| + } |
| bool success = WebPEncode(&config, &picture); |
| WebPPictureFree(&picture); |
| return success; |
| } |
| -bool WEBPImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsigned char>* output) |
| +bool WEBPImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsigned char>* output, WEBPImageEncoder::Mode mode) |
|
Noel Gordon
2015/08/26 23:43:14
FIXME: since SkBitmap is being removed from chrome
Noel Gordon
2015/08/27 12:43:00
https://code.google.com/p/chromium/issues/detail?i
urvang
2015/08/27 17:18:23
Nice! That explains why I never hit this encoder i
|
| { |
| SkAutoLockPixels bitmapLock(bitmap); |
| if (bitmap.colorType() != kN32_SkColorType || !bitmap.getPixels()) |
| return false; // Only support 32 bit/pixel skia bitmaps. |
| - return encodePixels(IntSize(bitmap.width(), bitmap.height()), static_cast<unsigned char *>(bitmap.getPixels()), true, quality, output); |
| + return encodePixels(IntSize(bitmap.width(), bitmap.height()), static_cast<unsigned char *>(bitmap.getPixels()), true, quality, output, mode); |
| } |
| -bool WEBPImageEncoder::encode(const ImageDataBuffer& imageData, int quality, Vector<unsigned char>* output) |
| +bool WEBPImageEncoder::encode(const ImageDataBuffer& imageData, int quality, Vector<unsigned char>* output, WEBPImageEncoder::Mode mode) |
| { |
| if (!imageData.pixels()) |
| return false; |
| - return encodePixels(IntSize(imageData.width(), imageData.height()), imageData.pixels(), false, quality, output); |
| + return encodePixels(IntSize(imageData.width(), imageData.height()), imageData.pixels(), false, quality, output, mode); |
| } |
| } // namespace blink |