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 |