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

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

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Addressing comments. 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 // TODO(zakerinasab): Replace sRGB with a call to
70 // ImageDecoder::globalTargetColorSpace() when the crash problem on Mac
71 // is fixed.
xidachen 2016/11/24 21:07:58 Please file a bug indicating that there is a crash
72 parsedOptions.dstColorSpace =
73 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
74 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
75 } else {
76 if (options.colorSpaceConversion() == "default" ||
77 options.colorSpaceConversion() == "srgb") {
78 parsedOptions.dstColorSpace =
79 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
80 parsedOptions.dstColorType = SkColorType::kN32_SkColorType;
81 } else if (options.colorSpaceConversion() == "linear-rgb") {
82 parsedOptions.bytesPerPixel = 8;
83 parsedOptions.dstColorSpace =
84 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
85 parsedOptions.dstColorType = SkColorType::kRGBA_F16_SkColorType;
86 } else {
87 NOTREACHED()
88 << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
89 << options.colorSpaceConversion();
90 }
91 }
92 }
93
66 int sourceWidth = sourceSize.width(); 94 int sourceWidth = sourceSize.width();
67 int sourceHeight = sourceSize.height(); 95 int sourceHeight = sourceSize.height();
68 if (!cropRect) { 96 if (!cropRect) {
69 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight); 97 parsedOptions.cropRect = IntRect(0, 0, sourceWidth, sourceHeight);
70 } else { 98 } else {
71 parsedOptions.cropRect = normalizeRect(*cropRect); 99 parsedOptions.cropRect = normalizeRect(*cropRect);
72 } 100 }
73 if (!options.hasResizeWidth() && !options.hasResizeHeight()) { 101 if (!options.hasResizeWidth() && !options.hasResizeHeight()) {
74 parsedOptions.resizeWidth = parsedOptions.cropRect.width(); 102 parsedOptions.resizeWidth = parsedOptions.cropRect.width();
75 parsedOptions.resizeHeight = parsedOptions.cropRect.height(); 103 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(), 253 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(),
226 kN32_SkColorType, kPremul_SkAlphaType); 254 kN32_SkColorType, kPremul_SkAlphaType);
227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 255 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
228 if (!dstPixels) 256 if (!dstPixels)
229 return nullptr; 257 return nullptr;
230 return newSkImageFromRaster( 258 return newSkImageFromRaster(
231 info, std::move(dstPixels), 259 info, std::move(dstPixels),
232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 260 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
233 } 261 }
234 262
263 static sk_sp<SkImage> applyColorSpaceConversion(
264 sk_sp<SkImage> image,
265 const ParsedOptions& parsedOptions) {
266 if (!parsedOptions.dstColorSpace)
267 return image;
268
269 SkImageInfo imageInfo = SkImageInfo::Make(
270 image->width(), image->height(), parsedOptions.dstColorType,
271 image->alphaType(), parsedOptions.dstColorSpace);
272 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
273 surface->getCanvas()->drawImage(image, 0, 0);
274 return surface->makeImageSnapshot();
275 }
276
235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( 277 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder(
236 std::unique_ptr<ImageDecoder> decoder) { 278 std::unique_ptr<ImageDecoder> decoder) {
237 if (!decoder->frameCount()) 279 if (!decoder->frameCount())
238 return nullptr; 280 return nullptr;
239 ImageFrame* frame = decoder->frameBufferAtIndex(0); 281 ImageFrame* frame = decoder->frameBufferAtIndex(0);
240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) 282 if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
241 return nullptr; 283 return nullptr;
242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); 284 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty());
243 return frame->finalizePixelsAndGetImage(); 285 return frame->finalizePixelsAndGetImage();
244 } 286 }
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 colorSpaceOp)); 357 colorSpaceOp));
316 if (!decoder) 358 if (!decoder)
317 return nullptr; 359 return nullptr;
318 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); 360 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder));
319 if (!skiaImage) 361 if (!skiaImage)
320 return nullptr; 362 return nullptr;
321 } 363 }
322 364
323 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { 365 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) {
324 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); 366 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect);
367 if (parsedOptions.dstColorSpace) {
368 croppedSkImage = applyColorSpaceConversion(croppedSkImage, parsedOptions);
369 }
325 if (parsedOptions.flipY) 370 if (parsedOptions.flipY)
326 return StaticBitmapImage::create(flipSkImageVertically( 371 return StaticBitmapImage::create(flipSkImageVertically(
327 croppedSkImage.get(), parsedOptions.premultiplyAlpha 372 croppedSkImage.get(), parsedOptions.premultiplyAlpha
328 ? PremultiplyAlpha 373 ? PremultiplyAlpha
329 : DontPremultiplyAlpha)); 374 : DontPremultiplyAlpha));
330 // Special case: The first parameter image is unpremul but we need to turn 375 // Special case: The first parameter image is unpremul but we need to turn
331 // it into premul. 376 // it into premul.
332 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) 377 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha)
333 return StaticBitmapImage::create( 378 return StaticBitmapImage::create(
334 unPremulSkImageToPremul(croppedSkImage.get())); 379 unPremulSkImageToPremul(croppedSkImage.get()));
(...skipping 26 matching lines...) Expand all
361 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth, 406 SkRect drawDstRect = SkRect::MakeXYWH(0, 0, parsedOptions.resizeWidth,
362 parsedOptions.resizeHeight); 407 parsedOptions.resizeHeight);
363 SkPaint paint; 408 SkPaint paint;
364 paint.setFilterQuality(parsedOptions.resizeQuality); 409 paint.setFilterQuality(parsedOptions.resizeQuality);
365 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, 410 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect,
366 &paint); 411 &paint);
367 } else { 412 } else {
368 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); 413 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop);
369 } 414 }
370 skiaImage = surface->makeImageSnapshot(); 415 skiaImage = surface->makeImageSnapshot();
416 if (parsedOptions.dstColorSpace)
417 skiaImage = applyColorSpaceConversion(skiaImage, parsedOptions);
371 418
372 if (parsedOptions.premultiplyAlpha) { 419 if (parsedOptions.premultiplyAlpha) {
373 if (imageFormat == DontPremultiplyAlpha) 420 if (imageFormat == DontPremultiplyAlpha)
374 return StaticBitmapImage::create( 421 return StaticBitmapImage::create(
375 unPremulSkImageToPremul(skiaImage.get())); 422 unPremulSkImageToPremul(skiaImage.get()));
376 return StaticBitmapImage::create(std::move(skiaImage)); 423 return StaticBitmapImage::create(std::move(skiaImage));
377 } 424 }
378 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 425 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
379 } 426 }
380 427
381 ImageBitmap::ImageBitmap(HTMLImageElement* image, 428 ImageBitmap::ImageBitmap(HTMLImageElement* image,
382 Optional<IntRect> cropRect, 429 Optional<IntRect> cropRect,
383 Document* document, 430 Document* document,
384 const ImageBitmapOptions& options) { 431 const ImageBitmapOptions& options) {
385 RefPtr<Image> input = image->cachedImage()->getImage(); 432 RefPtr<Image> input = image->cachedImage()->getImage();
386 ParsedOptions parsedOptions = 433 ParsedOptions parsedOptions =
387 parseOptions(options, cropRect, image->bitmapSourceSize()); 434 parseOptions(options, cropRect, image->bitmapSourceSize());
388 if (dstBufferSizeHasOverflow(parsedOptions)) 435 if (dstBufferSizeHasOverflow(parsedOptions))
389 return; 436 return;
390 437
391 if (options.colorSpaceConversion() == "none") { 438 m_image =
392 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 439 cropImage(input.get(), parsedOptions, PremultiplyAlpha,
393 ImageDecoder::ColorSpaceIgnored); 440 parsedOptions.dstColorSpace ? ImageDecoder::ColorSpaceApplied
394 } else { 441 : ImageDecoder::ColorSpaceIgnored);
395 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha,
396 ImageDecoder::ColorSpaceApplied);
397 }
398 if (!m_image) 442 if (!m_image)
399 return; 443 return;
400 // In the case where the source image is lazy-decoded, m_image may not be in 444 // In the case where the source image is lazy-decoded, m_image may not be in
401 // a decoded state, we trigger it here. 445 // a decoded state, we trigger it here.
402 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); 446 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame();
403 SkPixmap pixmap; 447 SkPixmap pixmap;
404 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 448 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
405 sk_sp<SkSurface> surface = 449 sk_sp<SkSurface> surface =
406 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); 450 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height());
407 surface->getCanvas()->drawImage(skImage, 0, 0); 451 surface->getCanvas()->drawImage(skImage, 0, 0);
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, 906 void ImageBitmap::adjustDrawRects(FloatRect* srcRect,
863 FloatRect* dstRect) const {} 907 FloatRect* dstRect) const {}
864 908
865 FloatSize ImageBitmap::elementSize(const FloatSize&) const { 909 FloatSize ImageBitmap::elementSize(const FloatSize&) const {
866 return FloatSize(width(), height()); 910 return FloatSize(width(), height());
867 } 911 }
868 912
869 DEFINE_TRACE(ImageBitmap) {} 913 DEFINE_TRACE(ImageBitmap) {}
870 914
871 } // namespace blink 915 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698