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

Side by Side 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, 3 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2011, Google Inc. All rights reserved. 2 * Copyright (c) 2011, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 28 matching lines...) Expand all
39 typedef int (*WebPImporter)(WebPPicture* const, const uint8_t* const data, int r owStride); 39 typedef int (*WebPImporter)(WebPPicture* const, const uint8_t* const data, int r owStride);
40 40
41 namespace blink { 41 namespace blink {
42 42
43 static int writeOutput(const uint8_t* data, size_t size, const WebPPicture* cons t picture) 43 static int writeOutput(const uint8_t* data, size_t size, const WebPPicture* cons t picture)
44 { 44 {
45 static_cast<Vector<unsigned char>*>(picture->custom_ptr)->append(data, size) ; 45 static_cast<Vector<unsigned char>*>(picture->custom_ptr)->append(data, size) ;
46 return 1; 46 return 1;
47 } 47 }
48 48
49 static bool rgbPictureImport(const unsigned char* pixels, bool premultiplied, We bPImporter importRGBX, WebPImporter importRGB, WebPPicture* picture) 49 static bool rgbaPictureImport(const unsigned char* pixels, bool premultiplied, W ebPImporter importRGBA, WebPPicture* picture)
50 { 50 {
51 if (premultiplied) 51 if (!premultiplied)
52 return importRGBX(picture, pixels, picture->width * 4); 52 return importRGBA(picture, pixels, picture->width * 4);
53 53
54 // Write the RGB pixels to an rgb data buffer, alpha premultiplied, then imp ort the rgb data. 54 static const SkUnPreMultiply::Scale* scale = SkUnPreMultiply::GetScaleTable( );
55 55
56 size_t pixelCount = picture->height * picture->width; 56 size_t pixelCount = picture->height * picture->width;
57 57 OwnPtr<unsigned char[]> rgba = adoptArrayPtr(new unsigned char[pixelCount * 4]);
58 OwnPtr<unsigned char[]> rgb = adoptArrayPtr(new unsigned char[pixelCount * 3 ]); 58 if (!rgba.get())
59 if (!rgb.get())
60 return false; 59 return false;
61 60
62 for (unsigned char* data = rgb.get(); pixelCount-- > 0; pixels += 4) { 61 for (unsigned char* data = rgba.get(); pixelCount-- > 0; pixels += 4) {
63 unsigned char alpha = pixels[3]; 62 unsigned char alpha = pixels[3];
64 if (alpha != 255) { 63 if ((alpha != 0) && (alpha != 255)) {
65 *data++ = SkMulDiv255Round(pixels[0], alpha); 64 *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[0]);
66 *data++ = SkMulDiv255Round(pixels[1], alpha); 65 *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[1]);
67 *data++ = SkMulDiv255Round(pixels[2], alpha); 66 *data++ = SkUnPreMultiply::ApplyScale(scale[alpha], pixels[2]);
67 *data++ = alpha;
68 } else { 68 } else {
69 *data++ = pixels[0]; 69 *data++ = pixels[0];
70 *data++ = pixels[1]; 70 *data++ = pixels[1];
71 *data++ = pixels[2]; 71 *data++ = pixels[2];
72 *data++ = alpha;
72 } 73 }
73 } 74 }
74 75
75 return importRGB(picture, rgb.get(), picture->width * 3); 76 return importRGBA(picture, rgba.get(), picture->width * 4);
76 } 77 }
77 78
78 template <bool Premultiplied> inline bool importPictureBGRX(const unsigned char* pixels, WebPPicture* picture) 79 template <bool Premultiplied> inline bool importPictureBGRA(const unsigned char* pixels, WebPPicture* picture)
79 { 80 {
80 return rgbPictureImport(pixels, Premultiplied, &WebPPictureImportBGRX, &WebP PictureImportBGR, picture); 81 return rgbaPictureImport(pixels, Premultiplied, &WebPPictureImportBGRA, pict ure);
81 } 82 }
82 83
83 template <bool Premultiplied> inline bool importPictureRGBX(const unsigned char* pixels, WebPPicture* picture) 84 template <bool Premultiplied> inline bool importPictureRGBA(const unsigned char* pixels, WebPPicture* picture)
84 { 85 {
85 return rgbPictureImport(pixels, Premultiplied, &WebPPictureImportRGBX, &WebP PictureImportRGB, picture); 86 return rgbaPictureImport(pixels, Premultiplied, &WebPPictureImportRGBA, pict ure);
86 } 87 }
87 88
88 static bool platformPremultipliedImportPicture(const unsigned char* pixels, WebP Picture* picture) 89 static bool platformPremultipliedImportPicture(const unsigned char* pixels, WebP Picture* picture)
89 { 90 {
90 if (SK_B32_SHIFT) // Android 91 if (SK_B32_SHIFT) // Android
91 return importPictureRGBX<true>(pixels, picture); 92 return importPictureRGBA<true>(pixels, picture);
92 93
93 return importPictureBGRX<true>(pixels, picture); 94 return importPictureBGRA<true>(pixels, picture);
94 } 95 }
95 96
96 static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool pr emultiplied, int quality, Vector<unsigned char>* output) 97 static bool encodePixels(IntSize imageSize, const unsigned char* pixels, bool pr emultiplied, int quality, Vector<unsigned char>* output, WEBPImageEncoder::Mode mode)
97 { 98 {
98 if (imageSize.width() <= 0 || imageSize.width() > WEBP_MAX_DIMENSION) 99 if (imageSize.width() <= 0 || imageSize.width() > WEBP_MAX_DIMENSION)
99 return false; 100 return false;
100 if (imageSize.height() <= 0 || imageSize.height() > WEBP_MAX_DIMENSION) 101 if (imageSize.height() <= 0 || imageSize.height() > WEBP_MAX_DIMENSION)
101 return false; 102 return false;
102 103
103 WebPConfig config; 104 WebPConfig config;
104 if (!WebPConfigInit(&config)) 105 if (!WebPConfigInit(&config))
105 return false; 106 return false;
106 WebPPicture picture; 107 WebPPicture picture;
107 if (!WebPPictureInit(&picture)) 108 if (!WebPPictureInit(&picture))
108 return false; 109 return false;
109 110
110 picture.width = imageSize.width(); 111 picture.width = imageSize.width();
111 picture.height = imageSize.height(); 112 picture.height = imageSize.height();
113 if (quality > 99 || mode == WEBPImageEncoder::Lossless)
114 picture.use_argb = 1;
112 115
acterhd 2015/08/27 17:18:19 I'm used backward compatibility with lossy without
113 if (premultiplied && !platformPremultipliedImportPicture(pixels, &picture)) 116 if (premultiplied && !platformPremultipliedImportPicture(pixels, &picture))
114 return false; 117 return false;
115 if (!premultiplied && !importPictureRGBX<false>(pixels, &picture)) 118 if (!premultiplied && !importPictureRGBA<false>(pixels, &picture))
116 return false; 119 return false;
117 120
118 picture.custom_ptr = output; 121 picture.custom_ptr = output;
119 picture.writer = &writeOutput; 122 picture.writer = &writeOutput;
120 config.quality = quality; 123
121 config.method = 3; 124 if (mode == WEBPImageEncoder::Lossless) {
125 // libeweb > 0x0202 has a lossless preset http://bit.ly/1Pz9IkE
126 // api, but it is not in chrome yet. Approximate it.
127 ASSERT(quality >= 0 && quality <= 100);
128 config.quality = quality;
129 config.method = (quality * 6) / 100;
urvang 2015/08/27 17:18:23 Large method values are pretty impractical: e.g. q
130 config.lossless = 1;
131 } else if (quality > 99) {
acterhd 2015/08/27 17:18:19 Bad idea, particularly for video (WebM) encoders w
132 // Use a middle-of-the-road quality, lossless webp encoding
133 // -- to balance speed with compresssion time
134 // -- to maintain sharpness (for text, see JPEG 4:4:4).
135 // FIXME: should we use WebPPictureSmartARGBToYUVA() instead
136 // for this case? Maybe compare it with the approach here in
137 // terms of encoding speed and quality.
Noel Gordon 2015/08/26 23:13:49 _and_ filesize.
138 config.quality = 75;
Noel Gordon 2015/08/26 23:52:03 FIXME: use WEBPImageEncoder::DefaultCompressionQua
139 config.method = 4;
140 config.lossless = 1;
urvang 2015/08/27 17:18:23 We have a separate setting for lossless, so qualit
141 } else {
142 config.quality = quality;
143 config.method = 3;
144 config.lossless = 0;
145 }
122 146
123 bool success = WebPEncode(&config, &picture); 147 bool success = WebPEncode(&config, &picture);
124 WebPPictureFree(&picture); 148 WebPPictureFree(&picture);
125 return success; 149 return success;
126 } 150 }
127 151
128 bool WEBPImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsign ed char>* output) 152 bool WEBPImageEncoder::encode(const SkBitmap& bitmap, int quality, Vector<unsign ed 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
129 { 153 {
130 SkAutoLockPixels bitmapLock(bitmap); 154 SkAutoLockPixels bitmapLock(bitmap);
131 155
132 if (bitmap.colorType() != kN32_SkColorType || !bitmap.getPixels()) 156 if (bitmap.colorType() != kN32_SkColorType || !bitmap.getPixels())
133 return false; // Only support 32 bit/pixel skia bitmaps. 157 return false; // Only support 32 bit/pixel skia bitmaps.
134 158
135 return encodePixels(IntSize(bitmap.width(), bitmap.height()), static_cast<un signed char *>(bitmap.getPixels()), true, quality, output); 159 return encodePixels(IntSize(bitmap.width(), bitmap.height()), static_cast<un signed char *>(bitmap.getPixels()), true, quality, output, mode);
136 } 160 }
137 161
138 bool WEBPImageEncoder::encode(const ImageDataBuffer& imageData, int quality, Vec tor<unsigned char>* output) 162 bool WEBPImageEncoder::encode(const ImageDataBuffer& imageData, int quality, Vec tor<unsigned char>* output, WEBPImageEncoder::Mode mode)
139 { 163 {
140 if (!imageData.pixels()) 164 if (!imageData.pixels())
141 return false; 165 return false;
142 166
143 return encodePixels(IntSize(imageData.width(), imageData.height()), imageDat a.pixels(), false, quality, output); 167 return encodePixels(IntSize(imageData.width(), imageData.height()), imageDat a.pixels(), false, quality, output, mode);
144 } 168 }
145 169
146 } // namespace blink 170 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698