diff options
author | glen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-28 04:17:59 +0000 |
---|---|---|
committer | glen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-28 04:17:59 +0000 |
commit | a0669d0100750d2629de8fb552ec39512a752a69 (patch) | |
tree | 9b1286f7cd1f949c93d50730fd910933f9d30295 /skia/ext/image_operations.cc | |
parent | 6dfed102065bda2e23541a5bf871b97258174fe3 (diff) | |
download | chromium_src-a0669d0100750d2629de8fb552ec39512a752a69.zip chromium_src-a0669d0100750d2629de8fb552ec39512a752a69.tar.gz chromium_src-a0669d0100750d2629de8fb552ec39512a752a69.tar.bz2 |
Add bitmap manipulation functions in advance of themes.
HSLToSkColor premultiplies its output, should this instead live in the ImageOperations bitmap munging code?
Review URL: http://codereview.chromium.org/79082
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14712 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext/image_operations.cc')
-rw-r--r-- | skia/ext/image_operations.cc | 210 |
1 files changed, 206 insertions, 4 deletions
diff --git a/skia/ext/image_operations.cc b/skia/ext/image_operations.cc index 4a1438b..2c6c2c2 100644 --- a/skia/ext/image_operations.cc +++ b/skia/ext/image_operations.cc @@ -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 @@ SkBitmap ImageOperations::Resize(const SkBitmap& source, "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 @@ SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, // 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 @@ SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, 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. + SkPMColor 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, + 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 |