Chromium Code Reviews| Index: skia/ext/image_operations.cc |
| =================================================================== |
| --- skia/ext/image_operations.cc (revision 13970) |
| +++ skia/ext/image_operations.cc (working copy) |
| @@ -15,6 +15,8 @@ |
| #include "base/stack_container.h" |
| #include "SkBitmap.h" |
| #include "skia/ext/convolver.h" |
| +#include "skia/include/SkColorPriv.h" |
| +#include "skia/ext/skia_utils.h" |
| namespace skia { |
| @@ -263,7 +265,7 @@ |
| "The supplied subset does not fall within the destination image."; |
| // If the size of source or destination is 0, i.e. 0x0, 0xN or Nx0, just |
| - // return empty |
| + // return empty. |
| if (source.width() < 1 || source.height() < 1 || |
| dest_width < 1 || dest_height < 1) |
| return SkBitmap(); |
| @@ -315,11 +317,10 @@ |
| // Optimize for case where we won't need to blend anything. |
| static const double alpha_min = 1.0 / 255; |
| static const double alpha_max = 254.0 / 255; |
| - if (alpha < alpha_min) { |
| + if (alpha < alpha_min) |
| return first; |
| - } else if (alpha > alpha_max) { |
| + else if (alpha > alpha_max) |
| return second; |
| - } |
| SkAutoLockPixels lock_first(first); |
| SkAutoLockPixels lock_second(second); |
| @@ -361,5 +362,206 @@ |
| return blended; |
| } |
| +// static |
| +SkBitmap ImageOperations::CreateMaskedBitmap(const SkBitmap& rgb, |
| + const SkBitmap& alpha) { |
| + DCHECK(rgb.width() == alpha.width()); |
| + DCHECK(rgb.height() == alpha.height()); |
| + DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel()); |
| + DCHECK(rgb.config() == SkBitmap::kARGB_8888_Config); |
| + DCHECK(alpha.config() == SkBitmap::kARGB_8888_Config); |
| + |
| + SkBitmap masked; |
| + masked.setConfig(SkBitmap::kARGB_8888_Config, rgb.width(), rgb.height(), 0); |
| + masked.allocPixels(); |
| + masked.eraseARGB(0, 0, 0, 0); |
| + |
| + SkAutoLockPixels lock_rgb(rgb); |
| + SkAutoLockPixels lock_alpha(alpha); |
| + SkAutoLockPixels lock_masked(masked); |
| + |
| + for (int y = 0; y < rgb.height(); y++) { |
| + uint32* rgb_row = rgb.getAddr32(0, y); |
| + uint32* alpha_row = alpha.getAddr32(0, y); |
| + uint32* dst_row = masked.getAddr32(0, y); |
| + |
| + for (int x = 0; x < rgb.width(); x++) { |
| + uint32 alpha_pixel = alpha_row[x]; |
| + uint32 rgb_pixel = rgb_row[x]; |
| + |
| + int alpha = SkColorGetA(alpha_pixel); |
| + dst_row[x] = SkColorSetARGB(alpha, |
| + SkAlphaMul(SkColorGetR(rgb_pixel), alpha), |
| + SkAlphaMul(SkColorGetG(rgb_pixel), alpha), |
| + SkAlphaMul(SkColorGetB(rgb_pixel), alpha)); |
| + } |
| + } |
| + |
| + return masked; |
| +} |
| + |
| +SkBitmap ImageOperations::CreateBlurredBitmap(const SkBitmap& bitmap, |
| + int blur_amount ) { |
| + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); |
| + |
| + // Blur factor (1 divided by how many pixels the blur takes place over). |
| + double v = 1.0 / pow(static_cast<double>(blur_amount * 2 + 1), 2); |
| + |
| + SkBitmap blurred; |
| + blurred.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), |
| + bitmap.height(), 0); |
| + blurred.allocPixels(); |
| + blurred.eraseARGB(0, 0, 0, 0); |
| + |
| + SkAutoLockPixels lock_bitmap(bitmap); |
| + SkAutoLockPixels lock_blurred(blurred); |
| + |
| + // Loop through every pixel in the image. |
| + for (int y = 0; y < bitmap.height(); y++) { // Skip top and bottom edges. |
| + uint32* dst_row = blurred.getAddr32(0, y); |
| + |
| + for (int x = 0; x < bitmap.width(); x++) { // Skip left and right edges. |
| + // Sums for this pixel. |
| + double a = 0; |
| + double r = 0; |
| + double g = 0; |
| + double b = 0; |
| + |
| + for (int ky = -blur_amount; ky <= blur_amount; ky++) { |
| + for (int kx = -blur_amount; kx <= blur_amount; kx++) { |
| + // Calculate the adjacent pixel for this kernel point. Blurs |
| + // are wrapped. |
| + int bx = (x + kx) % bitmap.width(); |
| + while (bx < 0) |
| + bx += bitmap.width(); |
| + int by = (y + ky) % bitmap.height(); |
| + while (by < 0) |
| + by += bitmap.height(); |
| + |
| + uint32 src_pixel = bitmap.getAddr32(0, by)[bx]; |
| + |
| + a += v * static_cast<double>(SkColorGetA(src_pixel)); |
| + r += v * static_cast<double>(SkColorGetR(src_pixel)); |
| + g += v * static_cast<double>(SkColorGetG(src_pixel)); |
| + b += v * static_cast<double>(SkColorGetB(src_pixel)); |
| + } |
| + } |
| + |
| + dst_row[x] = SkColorSetARGB( |
| + static_cast<int>(a), |
| + static_cast<int>(r), |
| + static_cast<int>(g), |
| + static_cast<int>(b)); |
| + } |
| + } |
| + |
| + return blurred; |
| +} |
| + |
| +// static |
| +SkBitmap ImageOperations::CreateHSLShiftedBitmap(const SkBitmap& bitmap, |
| + float hsl_shift[3]) { |
| + DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config); |
| + |
| + SkBitmap shifted; |
| + shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), |
| + bitmap.height(), 0); |
| + shifted.allocPixels(); |
| + shifted.eraseARGB(0, 0, 0, 0); |
| + shifted.setIsOpaque(false); |
| + |
| + SkAutoLockPixels lock_bitmap(bitmap); |
| + SkAutoLockPixels lock_shifted(shifted); |
| + |
| + // Loop through the pixels of the original bitmap. |
| + for (int y = 0; y < bitmap.height(); y++) { |
| + SkColor* pixels = bitmap.getAddr32(0, y); |
| + SkColor* tinted_pixels = shifted.getAddr32(0, y); |
| + |
| + for (int x = 0; x < bitmap.width(); x++) { |
| + // Convert the color of this pixel to HSL. |
| + SkColor color = pixels[x]; |
| + int alpha = SkColorGetA(color); |
| + if (alpha != 255) { |
| + // We have to normalize the colors as they're pre-multiplied. |
| + double r = SkColorGetR(color) / static_cast<double>(alpha); |
| + double g = SkColorGetG(color) / static_cast<double>(alpha); |
| + double b = SkColorGetB(color) / static_cast<double>(alpha); |
| + color = SkColorSetARGB(255, |
| + static_cast<int>(r * 255.0), |
| + static_cast<int>(g * 255.0), |
| + static_cast<int>(b * 255.0)); |
| + } |
| + |
| + float pixel_hsl[3]; |
| + SkColorToHSL(color, pixel_hsl); |
| + |
| + // Replace the hue with the tint's hue. |
| + if (hsl_shift[0] >= 0) |
| + pixel_hsl[0] = hsl_shift[0]; |
| + |
| + // Change the saturation. |
| + if (hsl_shift[1] >= 0) { |
| + if (hsl_shift[1] <= 0.5) { |
| + pixel_hsl[1] *= hsl_shift[1] * 2.0; |
| + } else { |
| + pixel_hsl[1] = pixel_hsl[1] + (1.0 - pixel_hsl[1]) * |
| + ((hsl_shift[1] - 0.5) * 2.0); |
| + } |
| + } |
| + |
| + // Change the lightness. |
| + if (hsl_shift[2] >= 0) { |
| + if (hsl_shift[2] <= 0.5) { |
| + pixel_hsl[2] *= hsl_shift[2] * 2.0; |
| + } else { |
| + pixel_hsl[2] = pixel_hsl[2] + (1.0 - pixel_hsl[2]) * |
| + ((hsl_shift[2] - 0.5) * 2.0); |
| + } |
| + } |
| + |
| + // Convert back to RGB. |
| + tinted_pixels[x] = HSLToSKColor(alpha, pixel_hsl); |
| + } |
| + } |
| + |
| + return shifted; |
| +} |
| + |
| +// static |
| +SkBitmap ImageOperations::CreateTiledBitmap(const SkBitmap& source, |
|
brettw
2009/04/28 02:49:43
FWIW this could have been done by making a tiled b
|
| + int src_x, int src_y, |
| + int dst_w, int dst_h) { |
| + DCHECK(source.getConfig() == SkBitmap::kARGB_8888_Config); |
| + |
| + SkBitmap cropped; |
| + cropped.setConfig(SkBitmap::kARGB_8888_Config, dst_w, dst_h, 0); |
| + cropped.allocPixels(); |
| + cropped.eraseARGB(0, 0, 0, 0); |
| + |
| + SkAutoLockPixels lock_source(source); |
| + SkAutoLockPixels lock_cropped(cropped); |
| + |
| + // Loop through the pixels of the original bitmap. |
| + for (int y = 0; y < dst_h; y++) { |
| + int y_pix = (src_y + y) % source.height(); |
| + while (y_pix < 0) |
| + y_pix += source.height(); |
| + |
| + uint32* source_row = source.getAddr32(0, y_pix); |
| + uint32* dst_row = cropped.getAddr32(0, y); |
| + |
| + for (int x = 0; x < dst_w; x++) { |
| + int x_pix = (src_x + x) % source.width(); |
| + while (x_pix < 0) |
| + x_pix += source.width(); |
| + |
| + dst_row[x] = source_row[x_pix]; |
| + } |
| + } |
| + |
| + return cropped; |
| +} |
| + |
| } // namespace skia |