summaryrefslogtreecommitdiffstats
path: root/skia/ext/image_operations.cc
diff options
context:
space:
mode:
authorglen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-28 04:17:59 +0000
committerglen@chromium.org <glen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-28 04:17:59 +0000
commita0669d0100750d2629de8fb552ec39512a752a69 (patch)
tree9b1286f7cd1f949c93d50730fd910933f9d30295 /skia/ext/image_operations.cc
parent6dfed102065bda2e23541a5bf871b97258174fe3 (diff)
downloadchromium_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.cc210
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