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

Side by Side Diff: third_party/WebKit/Source/core/frame/ImageBitmap.cpp

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Addressing comments and unit tests issues Created 4 years 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 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/frame/ImageBitmap.h" 5 #include "core/frame/ImageBitmap.h"
6 6
7 #include "core/html/HTMLCanvasElement.h" 7 #include "core/html/HTMLCanvasElement.h"
8 #include "core/html/HTMLVideoElement.h" 8 #include "core/html/HTMLVideoElement.h"
9 #include "core/html/ImageData.h" 9 #include "core/html/ImageData.h"
10 #include "platform/graphics/skia/SkiaUtils.h" 10 #include "platform/graphics/skia/SkiaUtils.h"
(...skipping 13 matching lines...) Expand all
24 namespace { 24 namespace {
25 25
26 struct ParsedOptions { 26 struct ParsedOptions {
27 bool flipY = false; 27 bool flipY = false;
28 bool premultiplyAlpha = true; 28 bool premultiplyAlpha = true;
29 bool shouldScaleInput = false; 29 bool shouldScaleInput = false;
30 unsigned resizeWidth = 0; 30 unsigned resizeWidth = 0;
31 unsigned resizeHeight = 0; 31 unsigned resizeHeight = 0;
32 IntRect cropRect; 32 IntRect cropRect;
33 SkFilterQuality resizeQuality = kLow_SkFilterQuality; 33 SkFilterQuality resizeQuality = kLow_SkFilterQuality;
34 // This value should be changed in the future when we support
35 // createImageBitmap with higher bit depth, in the parseOptions() function.
36 // For now, it is always 4.
37 int bytesPerPixel = 4; 34 int bytesPerPixel = 4;
35 sk_sp<SkColorSpace> dstColorSpace = nullptr;
36 SkColorType dstColorType = SkColorType::kUnknown_SkColorType;
38 }; 37 };
39 38
40 // The following two functions are helpers used in cropImage 39 // The following two functions are helpers used in cropImage
41 static inline IntRect normalizeRect(const IntRect& rect) { 40 static inline IntRect normalizeRect(const IntRect& rect) {
42 return IntRect(std::min(rect.x(), rect.maxX()), 41 return IntRect(std::min(rect.x(), rect.maxX()),
43 std::min(rect.y(), rect.maxY()), 42 std::min(rect.y(), rect.maxY()),
44 std::max(rect.width(), -rect.width()), 43 std::max(rect.width(), -rect.width()),
45 std::max(rect.height(), -rect.height())); 44 std::max(rect.height(), -rect.height()));
46 } 45 }
47 46
48 ParsedOptions parseOptions(const ImageBitmapOptions& options, 47 ParsedOptions parseOptions(const ImageBitmapOptions& options,
49 Optional<IntRect> cropRect, 48 Optional<IntRect> cropRect,
50 IntSize sourceSize) { 49 IntSize sourceSize) {
51 ParsedOptions parsedOptions; 50 ParsedOptions parsedOptions;
52 if (options.imageOrientation() == imageOrientationFlipY) { 51 if (options.imageOrientation() == imageOrientationFlipY) {
53 parsedOptions.flipY = true; 52 parsedOptions.flipY = true;
54 } else { 53 } else {
55 parsedOptions.flipY = false; 54 parsedOptions.flipY = false;
56 DCHECK(options.imageOrientation() == imageBitmapOptionNone); 55 DCHECK(options.imageOrientation() == imageBitmapOptionNone);
57 } 56 }
58 if (options.premultiplyAlpha() == imageBitmapOptionNone) { 57 if (options.premultiplyAlpha() == imageBitmapOptionNone) {
59 parsedOptions.premultiplyAlpha = false; 58 parsedOptions.premultiplyAlpha = false;
60 } else { 59 } else {
61 parsedOptions.premultiplyAlpha = true; 60 parsedOptions.premultiplyAlpha = true;
62 DCHECK(options.premultiplyAlpha() == "default" || 61 DCHECK(options.premultiplyAlpha() == "default" ||
63 options.premultiplyAlpha() == "premultiply"); 62 options.premultiplyAlpha() == "premultiply");
64 } 63 }
65 64
65 if (options.colorSpaceConversion() != "none") {
66 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ||
67 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) {
68 DCHECK_EQ(options.colorSpaceConversion(), "default");
69 parsedOptions.dstColorSpace = ImageDecoder::globalTargetColorSpace();
70 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
71 } else {
72 if (options.colorSpaceConversion() == "default" ||
73 options.colorSpaceConversion() == "srgb") {
74 parsedOptions.dstColorSpace =
75 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
76 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
77 } else if (options.colorSpaceConversion() == "linear-rgb") {
78 parsedOptions.bytesPerPixel = 8;
79 parsedOptions.dstColorSpace =
80 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
81 parsedOptions.dstColorType = SkColorType::kRGBA_F16_SkColorType;
82 } else {
83 NOTREACHED()
84 << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
85 << options.colorSpaceConversion();
86 }
87 }
88 }
89
66 int sourceWidth = sourceSize.width(); 90 int sourceWidth = sourceSize.width();
67 int sourceHeight = sourceSize.height(); 91 int sourceHeight = sourceSize.height();
68 if (!cropRect) { 92 if (!cropRect) {
69 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); 93 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight);
70 } else { 94 } else {
71 parsedOptions.cropRect = normalizeRect(*cropRect); 95 parsedOptions.cropRect = normalizeRect(*cropRect);
72 } 96 }
73 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { 97 if (!options.hasResizeWidth() && !options.hasResizeHeight()) {
74 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); 98 parsedOptions.resizeWidth = parsedOptions.cropRect.width();
75 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); 99 parsedOptions.resizeHeight = parsedOptions.cropRect.height();
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 249 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(),
226 kN32_SkColorType, kPremul_SkAlphaType); 250 kN32_SkColorType, kPremul_SkAlphaType);
227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 251 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
228 if (!dstPixels) 252 if (!dstPixels)
229 return nullptr; 253 return nullptr;
230 return newSkImageFromRaster( 254 return newSkImageFromRaster(
231 info, std::move(dstPixels), 255 info, std::move(dstPixels),
232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 256 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
233 } 257 }
234 258
259 static sk_sp<SkImage> applyColorSpaceConversion(
260 sk_sp<SkImage> image,
261 const ParsedOptions& parsedOptions) {
262 if (!parsedOptions.dstColorSpace)
263 return image;
264
265 SkImageInfo imageInfo = SkImageInfo::Make(
266 image->width(), image->height(), parsedOptions.dstColorType,
267 image->alphaType(), parsedOptions.dstColorSpace);
268 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
269 surface->getCanvas()->drawImage(image, 0, 0);
270 return surface->makeImageSnapshot();
271 }
272
235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( 273 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder(
236 std::unique_ptr<ImageDecoder> decoder) { 274 std::unique_ptr<ImageDecoder> decoder) {
237 if (!decoder->frameCount()) 275 if (!decoder->frameCount())
238 return nullptr; 276 return nullptr;
239 ImageFrame* frame = decoder->frameBufferAtIndex(0); 277 ImageFrame* frame = decoder->frameBufferAtIndex(0);
240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) 278 if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
241 return nullptr; 279 return nullptr;
242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); 280 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty());
243 return frame->finalizePixelsAndGetImage(); 281 return frame->finalizePixelsAndGetImage();
244 } 282 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 colorSpaceOp)); 353 colorSpaceOp));
316 if (!decoder) 354 if (!decoder)
317 return nullptr; 355 return nullptr;
318 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); 356 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder));
319 if (!skiaImage) 357 if (!skiaImage)
320 return nullptr; 358 return nullptr;
321 } 359 }
322 360
323 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { 361 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) {
324 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); 362 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect);
363 if (parsedOptions.dstColorSpace) {
364 croppedSkImage = applyColorSpaceConversion(croppedSkImage, parsedOptions);
365 }
325 if (parsedOptions.flipY) 366 if (parsedOptions.flipY)
326 return StaticBitmapImage::create(flipSkImageVertically( 367 return StaticBitmapImage::create(flipSkImageVertically(
327 croppedSkImage.get(), parsedOptions.premultiplyAlpha 368 croppedSkImage.get(), parsedOptions.premultiplyAlpha
328 ? PremultiplyAlpha 369 ? PremultiplyAlpha
329 : DontPremultiplyAlpha)); 370 : DontPremultiplyAlpha));
330 // Special case: The first parameter image is unpremul but we need to turn 371 // Special case: The first parameter image is unpremul but we need to turn
331 // it into premul. 372 // it into premul.
332 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) 373 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha)
333 return StaticBitmapImage::create( 374 return StaticBitmapImage::create(
334 unPremulSkImageToPremul(croppedSkImage.get())); 375 unPremulSkImageToPremul(croppedSkImage.get()));
(...skipping 26 matching lines...) Expand all
361 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, 402 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth,
362 parsedOptions.resizeHeight); 403 parsedOptions.resizeHeight);
363 SkPaint paint; 404 SkPaint paint;
364 paint.setFilterQuality(parsedOptions.resizeQuality); 405 paint.setFilterQuality(parsedOptions.resizeQuality);
365 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, 406 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect,
366 &paint); 407 &paint);
367 } else { 408 } else {
368 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); 409 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop);
369 } 410 }
370 skiaImage = surface->makeImageSnapshot(); 411 skiaImage = surface->makeImageSnapshot();
412 if (parsedOptions.dstColorSpace)
413 skiaImage = applyColorSpaceConversion(skiaImage, parsedOptions);
371 414
372 if (parsedOptions.premultiplyAlpha) { 415 if (parsedOptions.premultiplyAlpha) {
373 if (imageFormat == DontPremultiplyAlpha) 416 if (imageFormat == DontPremultiplyAlpha)
374 return StaticBitmapImage::create( 417 return StaticBitmapImage::create(
375 unPremulSkImageToPremul(skiaImage.get())); 418 unPremulSkImageToPremul(skiaImage.get()));
376 return StaticBitmapImage::create(std::move(skiaImage)); 419 return StaticBitmapImage::create(std::move(skiaImage));
377 } 420 }
378 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 421 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
379 } 422 }
380 423
381 ImageBitmap::ImageBitmap(HTMLImageElement* image, 424 ImageBitmap::ImageBitmap(HTMLImageElement* image,
382 Optional<IntRect> cropRect, 425 Optional<IntRect> cropRect,
383 Document* document, 426 Document* document,
384 const ImageBitmapOptions& options) { 427 const ImageBitmapOptions& options) {
385 RefPtr<Image> input = image->cachedImage()->getImage(); 428 RefPtr<Image> input = image->cachedImage()->getImage();
386 ParsedOptions parsedOptions = 429 ParsedOptions parsedOptions =
387 parseOptions(options, cropRect, image->bitmapSourceSize()); 430 parseOptions(options, cropRect, image->bitmapSourceSize());
388 if (dstBufferSizeHasOverflow(parsedOptions)) 431 if (dstBufferSizeHasOverflow(parsedOptions))
389 return; 432 return;
390 433
391 if (options.colorSpaceConversion() == "none") { 434 m_image =
392 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 435 cropImage(input.get(), parsedOptions, PremultiplyAlpha,
393 ImageDecoder::ColorSpaceIgnored); 436 parsedOptions.dstColorSpace ? ImageDecoder::ColorSpaceApplied
394 } else { 437 : ImageDecoder::ColorSpaceIgnored);
xidachen 2016/11/24 18:41:01 Why not move the last argument to cropImage() func
zakerinasab 2016/11/24 20:13:42 We can't do it now as other constructors rely on t
395 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha,
396 ImageDecoder::ColorSpaceApplied);
397 }
398 if (!m_image) 438 if (!m_image)
399 return; 439 return;
400 // In the case where the source image is lazy-decoded, m_image may not be in 440 // In the case where the source image is lazy-decoded, m_image may not be in
401 // a decoded state, we trigger it here. 441 // a decoded state, we trigger it here.
402 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); 442 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame();
403 SkPixmap pixmap; 443 SkPixmap pixmap;
404 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 444 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
405 sk_sp<SkSurface> surface = 445 sk_sp<SkSurface> surface =
406 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); 446 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height());
407 surface->getCanvas()->drawImage(skImage, 0, 0); 447 surface->getCanvas()->drawImage(skImage, 0, 0);
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, 902 void ImageBitmap::adjustDrawRects(FloatRect* srcRect,
863 FloatRect* dstRect) const {} 903 FloatRect* dstRect) const {}
864 904
865 FloatSize ImageBitmap::elementSize(const FloatSize&) const { 905 FloatSize ImageBitmap::elementSize(const FloatSize&) const {
866 return FloatSize(width(), height()); 906 return FloatSize(width(), height());
867 } 907 }
868 908
869 DEFINE_TRACE(ImageBitmap) {} 909 DEFINE_TRACE(ImageBitmap) {}
870 910
871 } // namespace blink 911 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698