Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1039)

Unified Diff: Source/platform/image-encoders/skia/WEBPImageEncoder.cpp

Issue 1302423004: Support lossy and lossless <canvas>.toDataURL for webp (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698