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

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

Issue 2522693002: Color correct ImageBitmap(HTMLImageElement*) constructor (Closed)
Patch Set: Resolving issues Created 4 years, 1 month 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 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(), 225 SkImageInfo info = SkImageInfo::Make(input->width(), input->height(),
226 kN32_SkColorType, kPremul_SkAlphaType); 226 kN32_SkColorType, kPremul_SkAlphaType);
227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info); 227 RefPtr<Uint8Array> dstPixels = copySkImageData(input, info);
228 if (!dstPixels) 228 if (!dstPixels)
229 return nullptr; 229 return nullptr;
230 return newSkImageFromRaster( 230 return newSkImageFromRaster(
231 info, std::move(dstPixels), 231 info, std::move(dstPixels),
232 static_cast<unsigned>(input->width()) * info.bytesPerPixel()); 232 static_cast<unsigned>(input->width()) * info.bytesPerPixel());
233 } 233 }
234 234
235 static sk_sp<SkImage> applyColorSpaceConversion(
236 sk_sp<SkImage> image,
237 bool premultiplyAlpha,
238 const ImageBitmapOptions* options) {
239 // Valid values for colorSpaceConversion are "default", "srgb" and
240 // "linear-rgb" here.
241 if (options->colorSpaceConversion() != "default" &&
242 options->colorSpaceConversion() != "srgb" &&
243 options->colorSpaceConversion() != "linear-rgb") {
244 NOTREACHED()
245 << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
246 << options->colorSpaceConversion();
247 return image;
xidachen 2016/11/22 20:34:37 This part should be moved to the function parseOpt
248 }
249
250 bool colorCorrectRendering =
251 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
252 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
253
254 // If color correct rendering is not set, only "default" is accepted here.
255 if (options->colorSpaceConversion() != "default" && !colorCorrectRendering) {
256 NOTREACHED()
257 << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
258 << options->colorSpaceConversion();
259 return image;
xidachen 2016/11/22 20:34:37 This part should be moved to parseOptions() as wel
zakerinasab 2016/11/24 18:18:32 Done.
260 }
261
262 SkImageInfo imageInfo;
263 // If color space conversion is default and color correct rendering is
264 // not set, color correct the image to match display profile.
265 // For now we assume 8 bit per channel for display. This must be fixed
266 // to properly support color space conversion on HDR displays when
267 // they are supported in SkColorType.
268 if (options->colorSpaceConversion() == "default" && !colorCorrectRendering) {
269 imageInfo = SkImageInfo::Make(image->width(), image->height(),
270 SkColorType::kN32_SkColorType,
271 SkAlphaType::kPremul_SkAlphaType,
272 ImageDecoder::globalTargetColorSpace());
273
274 // If color space conversion is default and color correct rendering is
275 // set, color correct the image to sRGB.
276 } else if (options->colorSpaceConversion() == "default" ||
277 options->colorSpaceConversion() == "srgb") {
278 imageInfo = SkImageInfo::MakeS32(image->width(), image->height(),
279 SkAlphaType::kPremul_SkAlphaType);
280
281 } else if (options->colorSpaceConversion() == "linear-rgb") {
282 imageInfo = SkImageInfo::Make(
283 image->width(), image->height(), SkColorType::kRGBA_F16_SkColorType,
284 SkAlphaType::kPremul_SkAlphaType,
285 SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named));
286 }
287
288 sk_sp<SkSurface> surface = SkSurface::MakeRaster(imageInfo);
289 surface->getCanvas()->drawImage(image, 0, 0);
290 return surface->makeImageSnapshot();
291 }
292
235 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder( 293 sk_sp<SkImage> ImageBitmap::getSkImageFromDecoder(
236 std::unique_ptr<ImageDecoder> decoder) { 294 std::unique_ptr<ImageDecoder> decoder) {
237 if (!decoder->frameCount()) 295 if (!decoder->frameCount())
238 return nullptr; 296 return nullptr;
239 ImageFrame* frame = decoder->frameBufferAtIndex(0); 297 ImageFrame* frame = decoder->frameBufferAtIndex(0);
240 if (!frame || frame->getStatus() != ImageFrame::FrameComplete) 298 if (!frame || frame->getStatus() != ImageFrame::FrameComplete)
241 return nullptr; 299 return nullptr;
242 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty()); 300 DCHECK(!frame->bitmap().isNull() && !frame->bitmap().empty());
243 return frame->finalizePixelsAndGetImage(); 301 return frame->finalizePixelsAndGetImage();
244 } 302 }
(...skipping 25 matching lines...) Expand all
270 // The parameter imageFormat indicates whether the first parameter "image" is 328 // The parameter imageFormat indicates whether the first parameter "image" is
271 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in 329 // unpremultiplied or not. imageFormat = PremultiplyAlpha means the image is in
272 // premuliplied format For example, if the image is already in unpremultiplied 330 // premuliplied format For example, if the image is already in unpremultiplied
273 // format and we want the created ImageBitmap in the same format, then we don't 331 // format and we want the created ImageBitmap in the same format, then we don't
274 // need to use the ImageDecoder to decode the image. 332 // need to use the ImageDecoder to decode the image.
275 static PassRefPtr<StaticBitmapImage> cropImage( 333 static PassRefPtr<StaticBitmapImage> cropImage(
276 Image* image, 334 Image* image,
277 const ParsedOptions& parsedOptions, 335 const ParsedOptions& parsedOptions,
278 AlphaDisposition imageFormat = PremultiplyAlpha, 336 AlphaDisposition imageFormat = PremultiplyAlpha,
279 ImageDecoder::ColorSpaceOption colorSpaceOp = 337 ImageDecoder::ColorSpaceOption colorSpaceOp =
280 ImageDecoder::ColorSpaceApplied) { 338 ImageDecoder::ColorSpaceApplied,
339 const ImageBitmapOptions* imageBitmapOptions = nullptr) {
281 ASSERT(image); 340 ASSERT(image);
282 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height())); 341 IntRect imgRect(IntPoint(), IntSize(image->width(), image->height()));
283 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect); 342 const IntRect srcRect = intersection(imgRect, parsedOptions.cropRect);
284 343
285 // In the case when cropRect doesn't intersect the source image and it 344 // In the case when cropRect doesn't intersect the source image and it
286 // requires a umpremul image We immediately return a transparent black image 345 // requires a umpremul image We immediately return a transparent black image
287 // with cropRect.size() 346 // with cropRect.size()
288 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) { 347 if (srcRect.isEmpty() && !parsedOptions.premultiplyAlpha) {
289 SkImageInfo info = 348 SkImageInfo info =
290 SkImageInfo::Make(parsedOptions.resizeWidth, parsedOptions.resizeHeight, 349 SkImageInfo::Make(parsedOptions.resizeWidth, parsedOptions.resizeHeight,
(...skipping 24 matching lines...) Expand all
315 colorSpaceOp)); 374 colorSpaceOp));
316 if (!decoder) 375 if (!decoder)
317 return nullptr; 376 return nullptr;
318 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder)); 377 skiaImage = ImageBitmap::getSkImageFromDecoder(std::move(decoder));
319 if (!skiaImage) 378 if (!skiaImage)
320 return nullptr; 379 return nullptr;
321 } 380 }
322 381
323 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) { 382 if (parsedOptions.cropRect == srcRect && !parsedOptions.shouldScaleInput) {
324 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect); 383 sk_sp<SkImage> croppedSkImage = skiaImage->makeSubset(srcRect);
384 if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) {
385 croppedSkImage = applyColorSpaceConversion(
386 croppedSkImage, parsedOptions.premultiplyAlpha, imageBitmapOptions);
xidachen 2016/11/22 20:34:37 Pass |parsedOptions| instead of the last two argum
zakerinasab 2016/11/24 18:18:32 Done.
387 }
325 if (parsedOptions.flipY) 388 if (parsedOptions.flipY)
326 return StaticBitmapImage::create(flipSkImageVertically( 389 return StaticBitmapImage::create(flipSkImageVertically(
327 croppedSkImage.get(), parsedOptions.premultiplyAlpha 390 croppedSkImage.get(), parsedOptions.premultiplyAlpha
328 ? PremultiplyAlpha 391 ? PremultiplyAlpha
329 : DontPremultiplyAlpha)); 392 : DontPremultiplyAlpha));
330 // Special case: The first parameter image is unpremul but we need to turn 393 // Special case: The first parameter image is unpremul but we need to turn
331 // it into premul. 394 // it into premul.
332 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha) 395 if (parsedOptions.premultiplyAlpha && imageFormat == DontPremultiplyAlpha)
333 return StaticBitmapImage::create( 396 return StaticBitmapImage::create(
334 unPremulSkImageToPremul(croppedSkImage.get())); 397 unPremulSkImageToPremul(croppedSkImage.get()));
335 // Call preroll to trigger image decoding. 398 // Call preroll to trigger image decoding.
336 croppedSkImage->preroll(); 399 croppedSkImage->preroll();
337 return StaticBitmapImage::create(std::move(croppedSkImage)); 400 return StaticBitmapImage::create(std::move(croppedSkImage));
338 } 401 }
339 402
403 // Currently ImageDecoder assumes at most 8 bits per channel for the decoded
404 // image. When this is fixed, we should change this code to create the
405 // surface according to the color depth of the decoded image.
340 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul( 406 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(
341 parsedOptions.resizeWidth, parsedOptions.resizeHeight); 407 parsedOptions.resizeWidth, parsedOptions.resizeHeight);
342 if (!surface) 408 if (!surface)
343 return nullptr; 409 return nullptr;
344 if (srcRect.isEmpty()) 410 if (srcRect.isEmpty())
345 return StaticBitmapImage::create(surface->makeImageSnapshot()); 411 return StaticBitmapImage::create(surface->makeImageSnapshot());
346 412
347 SkScalar dstLeft = std::min(0, -parsedOptions.cropRect.x()); 413 SkScalar dstLeft = std::min(0, -parsedOptions.cropRect.x());
348 SkScalar dstTop = std::min(0, -parsedOptions.cropRect.y()); 414 SkScalar dstTop = std::min(0, -parsedOptions.cropRect.y());
349 if (parsedOptions.cropRect.x() < 0) 415 if (parsedOptions.cropRect.x() < 0)
(...skipping 12 matching lines...) Expand all
362 parsedOptions.resizeHeight); 428 parsedOptions.resizeHeight);
363 SkPaint paint; 429 SkPaint paint;
364 paint.setFilterQuality(parsedOptions.resizeQuality); 430 paint.setFilterQuality(parsedOptions.resizeQuality);
365 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect, 431 surface->getCanvas()->drawImageRect(skiaImage, drawSrcRect, drawDstRect,
366 &paint); 432 &paint);
367 } else { 433 } else {
368 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop); 434 surface->getCanvas()->drawImage(skiaImage, dstLeft, dstTop);
369 } 435 }
370 skiaImage = surface->makeImageSnapshot(); 436 skiaImage = surface->makeImageSnapshot();
371 437
438 if (colorSpaceOp == ImageDecoder::ColorSpaceApplied) {
439 skiaImage = applyColorSpaceConversion(
440 skiaImage, parsedOptions.premultiplyAlpha, imageBitmapOptions);
xidachen 2016/11/22 20:34:38 Pass |parsedOptions| instead of the last two argum
zakerinasab 2016/11/24 18:18:32 Done.
441 }
372 if (parsedOptions.premultiplyAlpha) { 442 if (parsedOptions.premultiplyAlpha) {
373 if (imageFormat == DontPremultiplyAlpha) 443 if (imageFormat == DontPremultiplyAlpha)
374 return StaticBitmapImage::create( 444 return StaticBitmapImage::create(
375 unPremulSkImageToPremul(skiaImage.get())); 445 unPremulSkImageToPremul(skiaImage.get()));
376 return StaticBitmapImage::create(std::move(skiaImage)); 446 return StaticBitmapImage::create(std::move(skiaImage));
377 } 447 }
378 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get())); 448 return StaticBitmapImage::create(premulSkImageToUnPremul(skiaImage.get()));
379 } 449 }
380 450
381 ImageBitmap::ImageBitmap(HTMLImageElement* image, 451 ImageBitmap::ImageBitmap(HTMLImageElement* image,
382 Optional<IntRect> cropRect, 452 Optional<IntRect> cropRect,
383 Document* document, 453 Document* document,
384 const ImageBitmapOptions& options) { 454 const ImageBitmapOptions& options) {
385 RefPtr<Image> input = image->cachedImage()->getImage(); 455 RefPtr<Image> input = image->cachedImage()->getImage();
386 ParsedOptions parsedOptions = 456 ParsedOptions parsedOptions =
387 parseOptions(options, cropRect, image->bitmapSourceSize()); 457 parseOptions(options, cropRect, image->bitmapSourceSize());
388 if (dstBufferSizeHasOverflow(parsedOptions)) 458 if (dstBufferSizeHasOverflow(parsedOptions))
389 return; 459 return;
390 460
391 if (options.colorSpaceConversion() == "none") { 461 if (options.colorSpaceConversion() == "none") {
392 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 462 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha,
393 ImageDecoder::ColorSpaceIgnored); 463 ImageDecoder::ColorSpaceIgnored);
394 } else { 464 } else {
395 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha, 465 m_image = cropImage(input.get(), parsedOptions, PremultiplyAlpha,
396 ImageDecoder::ColorSpaceApplied); 466 ImageDecoder::ColorSpaceApplied, &options);
xidachen 2016/11/22 20:34:37 This is not the best way, and it is caused by my o
zakerinasab 2016/11/24 18:18:32 For now we need to keep ImageDecoder::ColorSpaceOp
397 } 467 }
398 if (!m_image) 468 if (!m_image)
399 return; 469 return;
400 // In the case where the source image is lazy-decoded, m_image may not be in 470 // In the case where the source image is lazy-decoded, m_image may not be in
401 // a decoded state, we trigger it here. 471 // a decoded state, we trigger it here.
402 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame(); 472 sk_sp<SkImage> skImage = m_image->imageForCurrentFrame();
403 SkPixmap pixmap; 473 SkPixmap pixmap;
404 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) { 474 if (!skImage->isTextureBacked() && !skImage->peekPixels(&pixmap)) {
405 sk_sp<SkSurface> surface = 475 sk_sp<SkSurface> surface =
406 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height()); 476 SkSurface::MakeRasterN32Premul(skImage->width(), skImage->height());
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after
862 void ImageBitmap::adjustDrawRects(FloatRect* srcRect, 932 void ImageBitmap::adjustDrawRects(FloatRect* srcRect,
863 FloatRect* dstRect) const {} 933 FloatRect* dstRect) const {}
864 934
865 FloatSize ImageBitmap::elementSize(const FloatSize&) const { 935 FloatSize ImageBitmap::elementSize(const FloatSize&) const {
866 return FloatSize(width(), height()); 936 return FloatSize(width(), height());
867 } 937 }
868 938
869 DEFINE_TRACE(ImageBitmap) {} 939 DEFINE_TRACE(ImageBitmap) {}
870 940
871 } // namespace blink 941 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698