| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 #define _USE_MATH_DEFINES | 5 #define _USE_MATH_DEFINES |
| 6 #include <cmath> | 6 #include <cmath> |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "skia/ext/image_operations.h" | 10 #include "skia/ext/image_operations.h" |
| 11 | 11 |
| 12 #include "base/gfx/rect.h" | 12 #include "base/gfx/rect.h" |
| 13 #include "base/gfx/size.h" | 13 #include "base/gfx/size.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/stack_container.h" | 15 #include "base/stack_container.h" |
| 16 #include "SkBitmap.h" | 16 #include "SkBitmap.h" |
| 17 #include "skia/ext/convolver.h" | 17 #include "skia/ext/convolver.h" |
| 18 #include "skia/include/SkColorPriv.h" | |
| 19 #include "skia/ext/skia_utils.h" | |
| 20 | 18 |
| 21 namespace skia { | 19 namespace skia { |
| 22 | 20 |
| 23 // TODO(brettw) remove this and put this file in the skia namespace. | 21 // TODO(brettw) remove this and put this file in the skia namespace. |
| 24 using namespace gfx; | 22 using namespace gfx; |
| 25 | 23 |
| 26 namespace { | 24 namespace { |
| 27 | 25 |
| 28 // Returns the ceiling/floor as an integer. | 26 // Returns the ceiling/floor as an integer. |
| 29 inline int CeilInt(float val) { | 27 inline int CeilInt(float val) { |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 | 256 |
| 259 // static | 257 // static |
| 260 SkBitmap ImageOperations::Resize(const SkBitmap& source, | 258 SkBitmap ImageOperations::Resize(const SkBitmap& source, |
| 261 ResizeMethod method, | 259 ResizeMethod method, |
| 262 int dest_width, int dest_height, | 260 int dest_width, int dest_height, |
| 263 const gfx::Rect& dest_subset) { | 261 const gfx::Rect& dest_subset) { |
| 264 DCHECK(gfx::Rect(dest_width, dest_height).Contains(dest_subset)) << | 262 DCHECK(gfx::Rect(dest_width, dest_height).Contains(dest_subset)) << |
| 265 "The supplied subset does not fall within the destination image."; | 263 "The supplied subset does not fall within the destination image."; |
| 266 | 264 |
| 267 // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just | 265 // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just |
| 268 // return empty. | 266 // return empty |
| 269 if (source.width() < 1 || source.height() < 1 || | 267 if (source.width() < 1 || source.height() < 1 || |
| 270 dest_width < 1 || dest_height < 1) | 268 dest_width < 1 || dest_height < 1) |
| 271 return SkBitmap(); | 269 return SkBitmap(); |
| 272 | 270 |
| 273 SkAutoLockPixels locker(source); | 271 SkAutoLockPixels locker(source); |
| 274 | 272 |
| 275 ResizeFilter filter(method, source.width(), source.height(), | 273 ResizeFilter filter(method, source.width(), source.height(), |
| 276 dest_width, dest_height, dest_subset); | 274 dest_width, dest_height, dest_subset); |
| 277 | 275 |
| 278 // Get a source bitmap encompassing this touched area. We construct the | 276 // Get a source bitmap encompassing this touched area. We construct the |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 double alpha) { | 308 double alpha) { |
| 311 DCHECK(alpha <= 1 && alpha >= 0); | 309 DCHECK(alpha <= 1 && alpha >= 0); |
| 312 DCHECK(first.width() == second.width()); | 310 DCHECK(first.width() == second.width()); |
| 313 DCHECK(first.height() == second.height()); | 311 DCHECK(first.height() == second.height()); |
| 314 DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); | 312 DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); |
| 315 DCHECK(first.config() == SkBitmap::kARGB_8888_Config); | 313 DCHECK(first.config() == SkBitmap::kARGB_8888_Config); |
| 316 | 314 |
| 317 // Optimize for case where we won't need to blend anything. | 315 // Optimize for case where we won't need to blend anything. |
| 318 static const double alpha_min = 1.0 / 255; | 316 static const double alpha_min = 1.0 / 255; |
| 319 static const double alpha_max = 254.0 / 255; | 317 static const double alpha_max = 254.0 / 255; |
| 320 if (alpha < alpha_min) | 318 if (alpha < alpha_min) { |
| 321 return first; | 319 return first; |
| 322 else if (alpha > alpha_max) | 320 } else if (alpha > alpha_max) { |
| 323 return second; | 321 return second; |
| 322 } |
| 324 | 323 |
| 325 SkAutoLockPixels lock_first(first); | 324 SkAutoLockPixels lock_first(first); |
| 326 SkAutoLockPixels lock_second(second); | 325 SkAutoLockPixels lock_second(second); |
| 327 | 326 |
| 328 SkBitmap blended; | 327 SkBitmap blended; |
| 329 blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), | 328 blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), |
| 330 first.height(), 0); | 329 first.height(), 0); |
| 331 blended.allocPixels(); | 330 blended.allocPixels(); |
| 332 blended.eraseARGB(0, 0, 0, 0); | 331 blended.eraseARGB(0, 0, 0, 0); |
| 333 | 332 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 355 SkColorGetB(first_pixel) * first_alpha + | 354 SkColorGetB(first_pixel) * first_alpha + |
| 356 SkColorGetB(second_pixel) * alpha); | 355 SkColorGetB(second_pixel) * alpha); |
| 357 | 356 |
| 358 dst_row[x] = SkColorSetARGB(a, r, g, b); | 357 dst_row[x] = SkColorSetARGB(a, r, g, b); |
| 359 } | 358 } |
| 360 } | 359 } |
| 361 | 360 |
| 362 return blended; | 361 return blended; |
| 363 } | 362 } |
| 364 | 363 |
| 365 // static | |
| 366 SkBitmap ImageOperations::CreateMaskedBitmap(const SkBitmap& rgb, | |
| 367 const SkBitmap& alpha) { | |
| 368 DCHECK(rgb.width() == alpha.width()); | |
| 369 DCHECK(rgb.height() == alpha.height()); | |
| 370 DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel()); | |
| 371 DCHECK(rgb.config() == SkBitmap::kARGB_8888_Config); | |
| 372 DCHECK(alpha.config() == SkBitmap::kARGB_8888_Config); | |
| 373 | |
| 374 SkBitmap masked; | |
| 375 masked.setConfig(SkBitmap::kARGB_8888_Config, rgb.width(), rgb.height(), 0); | |
| 376 masked.allocPixels(); | |
| 377 masked.eraseARGB(0, 0, 0, 0); | |
| 378 | |
| 379 SkAutoLockPixels lock_rgb(rgb); | |
| 380 SkAutoLockPixels lock_alpha(alpha); | |
| 381 SkAutoLockPixels lock_masked(masked); | |
| 382 | |
| 383 for (int y = 0; y < rgb.height(); y++) { | |
| 384 uint32* rgb_row = rgb.getAddr32(0, y); | |
| 385 uint32* alpha_row = alpha.getAddr32(0, y); | |
| 386 uint32* dst_row = masked.getAddr32(0, y); | |
| 387 | |
| 388 for (int x = 0; x < rgb.width(); x++) { | |
| 389 uint32 alpha_pixel = alpha_row[x]; | |
| 390 uint32 rgb_pixel = rgb_row[x]; | |
| 391 | |
| 392 int alpha = SkColorGetA(alpha_pixel); | |
| 393 dst_row[x] = SkColorSetARGB(alpha, | |
| 394 SkAlphaMul(SkColorGetR(rgb_pixel), alpha), | |
| 395 SkAlphaMul(SkColorGetG(rgb_pixel), alpha), | |
| 396 SkAlphaMul(SkColorGetB(rgb_pixel), alpha)); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 return masked; | |
| 401 } | |
| 402 | |
| 403 SkBitmap ImageOperations::CreateBlurredBitmap(const SkBitmap& bitmap, | |
| 404 int blur_amount ) { | |
| 405 DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); | |
| 406 | |
| 407 // Blur factor (1 divided by how many pixels the blur takes place over). | |
| 408 double v = 1.0 / pow(static_cast<double>(blur_amount * 2 + 1), 2); | |
| 409 | |
| 410 SkBitmap blurred; | |
| 411 blurred.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), | |
| 412 bitmap.height(), 0); | |
| 413 blurred.allocPixels(); | |
| 414 blurred.eraseARGB(0, 0, 0, 0); | |
| 415 | |
| 416 SkAutoLockPixels lock_bitmap(bitmap); | |
| 417 SkAutoLockPixels lock_blurred(blurred); | |
| 418 | |
| 419 // Loop through every pixel in the image. | |
| 420 for (int y = 0; y < bitmap.height(); y++) { // Skip top and bottom edges. | |
| 421 uint32* dst_row = blurred.getAddr32(0, y); | |
| 422 | |
| 423 for (int x = 0; x < bitmap.width(); x++) { // Skip left and right edges. | |
| 424 // Sums for this pixel. | |
| 425 double a = 0; | |
| 426 double r = 0; | |
| 427 double g = 0; | |
| 428 double b = 0; | |
| 429 | |
| 430 for (int ky = -blur_amount; ky <= blur_amount; ky++) { | |
| 431 for (int kx = -blur_amount; kx <= blur_amount; kx++) { | |
| 432 // Calculate the adjacent pixel for this kernel point. Blurs | |
| 433 // are wrapped. | |
| 434 int bx = (x + kx) % bitmap.width(); | |
| 435 while (bx < 0) | |
| 436 bx += bitmap.width(); | |
| 437 int by = (y + ky) % bitmap.height(); | |
| 438 while (by < 0) | |
| 439 by += bitmap.height(); | |
| 440 | |
| 441 uint32 src_pixel = bitmap.getAddr32(0, by)[bx]; | |
| 442 | |
| 443 a += v * static_cast<double>(SkColorGetA(src_pixel)); | |
| 444 r += v * static_cast<double>(SkColorGetR(src_pixel)); | |
| 445 g += v * static_cast<double>(SkColorGetG(src_pixel)); | |
| 446 b += v * static_cast<double>(SkColorGetB(src_pixel)); | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 dst_row[x] = SkColorSetARGB( | |
| 451 static_cast<int>(a), | |
| 452 static_cast<int>(r), | |
| 453 static_cast<int>(g), | |
| 454 static_cast<int>(b)); | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 return blurred; | |
| 459 } | |
| 460 | |
| 461 // static | |
| 462 SkBitmap ImageOperations::CreateHSLShiftedBitmap(const SkBitmap& bitmap, | |
| 463 float hsl_shift[3]) { | |
| 464 DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); | |
| 465 | |
| 466 SkBitmap shifted; | |
| 467 shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), | |
| 468 bitmap.height(), 0); | |
| 469 shifted.allocPixels(); | |
| 470 shifted.eraseARGB(0, 0, 0, 0); | |
| 471 shifted.setIsOpaque(false); | |
| 472 | |
| 473 SkAutoLockPixels lock_bitmap(bitmap); | |
| 474 SkAutoLockPixels lock_shifted(shifted); | |
| 475 | |
| 476 // Loop through the pixels of the original bitmap. | |
| 477 for (int y = 0; y < bitmap.height(); y++) { | |
| 478 SkColor* pixels = bitmap.getAddr32(0, y); | |
| 479 SkColor* tinted_pixels = shifted.getAddr32(0, y); | |
| 480 | |
| 481 for (int x = 0; x < bitmap.width(); x++) { | |
| 482 // Convert the color of this pixel to HSL. | |
| 483 SkPMColor color = pixels[x]; | |
| 484 int alpha = SkColorGetA(color); | |
| 485 if (alpha != 255) { | |
| 486 // We have to normalize the colors as they're pre-multiplied. | |
| 487 double r = SkColorGetR(color) / static_cast<double>(alpha); | |
| 488 double g = SkColorGetG(color) / static_cast<double>(alpha); | |
| 489 double b = SkColorGetB(color) / static_cast<double>(alpha); | |
| 490 color = SkColorSetARGB(255, | |
| 491 static_cast<int>(r * 255.0), | |
| 492 static_cast<int>(g * 255.0), | |
| 493 static_cast<int>(b * 255.0)); | |
| 494 } | |
| 495 | |
| 496 float pixel_hsl[3]; | |
| 497 SkColorToHSL(color, pixel_hsl); | |
| 498 | |
| 499 // Replace the hue with the tint's hue. | |
| 500 if (hsl_shift[0] >= 0) | |
| 501 pixel_hsl[0] = hsl_shift[0]; | |
| 502 | |
| 503 // Change the saturation. | |
| 504 if (hsl_shift[1] >= 0) { | |
| 505 if (hsl_shift[1] <= 0.5) { | |
| 506 pixel_hsl[1] *= hsl_shift[1] * 2.0; | |
| 507 } else { | |
| 508 pixel_hsl[1] = pixel_hsl[1] + (1.0 - pixel_hsl[1]) * | |
| 509 ((hsl_shift[1] - 0.5) * 2.0); | |
| 510 } | |
| 511 } | |
| 512 | |
| 513 // Change the lightness. | |
| 514 if (hsl_shift[2] >= 0) { | |
| 515 if (hsl_shift[2] <= 0.5) { | |
| 516 pixel_hsl[2] *= hsl_shift[2] * 2.0; | |
| 517 } else { | |
| 518 pixel_hsl[2] = pixel_hsl[2] + (1.0 - pixel_hsl[2]) * | |
| 519 ((hsl_shift[2] - 0.5) * 2.0); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 // Convert back to RGB. | |
| 524 tinted_pixels[x] = HSLToSKColor(alpha, pixel_hsl); | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 return shifted; | |
| 529 } | |
| 530 | |
| 531 // static | |
| 532 SkBitmap ImageOperations::CreateTiledBitmap(const SkBitmap& source, | |
| 533 int src_x, int src_y, | |
| 534 int dst_w, int dst_h) { | |
| 535 DCHECK(source.getConfig() == SkBitmap::kARGB_8888_Config); | |
| 536 | |
| 537 SkBitmap cropped; | |
| 538 cropped.setConfig(SkBitmap::kARGB_8888_Config, dst_w, dst_h, 0); | |
| 539 cropped.allocPixels(); | |
| 540 cropped.eraseARGB(0, 0, 0, 0); | |
| 541 | |
| 542 SkAutoLockPixels lock_source(source); | |
| 543 SkAutoLockPixels lock_cropped(cropped); | |
| 544 | |
| 545 // Loop through the pixels of the original bitmap. | |
| 546 for (int y = 0; y < dst_h; y++) { | |
| 547 int y_pix = (src_y + y) % source.height(); | |
| 548 while (y_pix < 0) | |
| 549 y_pix += source.height(); | |
| 550 | |
| 551 uint32* source_row = source.getAddr32(0, y_pix); | |
| 552 uint32* dst_row = cropped.getAddr32(0, y); | |
| 553 | |
| 554 for (int x = 0; x < dst_w; x++) { | |
| 555 int x_pix = (src_x + x) % source.width(); | |
| 556 while (x_pix < 0) | |
| 557 x_pix += source.width(); | |
| 558 | |
| 559 dst_row[x] = source_row[x_pix]; | |
| 560 } | |
| 561 } | |
| 562 | |
| 563 return cropped; | |
| 564 } | |
| 565 | |
| 566 } // namespace skia | 364 } // namespace skia |
| 567 | 365 |
| OLD | NEW |