| 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 | 18 |
| 19 namespace gfx { | 19 namespace skia { |
| 20 |
| 21 // TODO(brettw) remove this and put this file in the skia namespace. |
| 22 using namespace gfx; |
| 20 | 23 |
| 21 namespace { | 24 namespace { |
| 22 | 25 |
| 23 // Returns the ceiling/floor as an integer. | 26 // Returns the ceiling/floor as an integer. |
| 24 inline int CeilInt(float val) { | 27 inline int CeilInt(float val) { |
| 25 return static_cast<int>(ceil(val)); | 28 return static_cast<int>(ceil(val)); |
| 26 } | 29 } |
| 27 inline int FloorInt(float val) { | 30 inline int FloorInt(float val) { |
| 28 return static_cast<int>(floor(val)); | 31 return static_cast<int>(floor(val)); |
| 29 } | 32 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 55 sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) | 58 sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) |
| 56 } | 59 } |
| 57 | 60 |
| 58 // ResizeFilter ---------------------------------------------------------------- | 61 // ResizeFilter ---------------------------------------------------------------- |
| 59 | 62 |
| 60 // Encapsulates computation and storage of the filters required for one complete | 63 // Encapsulates computation and storage of the filters required for one complete |
| 61 // resize operation. | 64 // resize operation. |
| 62 class ResizeFilter { | 65 class ResizeFilter { |
| 63 public: | 66 public: |
| 64 ResizeFilter(ImageOperations::ResizeMethod method, | 67 ResizeFilter(ImageOperations::ResizeMethod method, |
| 65 const Size& src_full_size, | 68 int src_full_width, int src_full_height, |
| 66 const Size& dest_size, | 69 int dest_width, int dest_height, |
| 67 const Rect& dest_subset); | 70 const gfx::Rect& dest_subset); |
| 68 | 71 |
| 69 // Returns the bounds in the input bitmap of data that is used in the output. | 72 // Returns the bounds in the input bitmap of data that is used in the output. |
| 70 // The filter offsets are within this rectangle. | 73 // The filter offsets are within this rectangle. |
| 71 const Rect& src_depend() { return src_depend_; } | 74 const gfx::Rect& src_depend() { return src_depend_; } |
| 72 | 75 |
| 73 // Returns the filled filter values. | 76 // Returns the filled filter values. |
| 74 const ConvolusionFilter1D& x_filter() { return x_filter_; } | 77 const ConvolusionFilter1D& x_filter() { return x_filter_; } |
| 75 const ConvolusionFilter1D& y_filter() { return y_filter_; } | 78 const ConvolusionFilter1D& y_filter() { return y_filter_; } |
| 76 | 79 |
| 77 private: | 80 private: |
| 78 // Returns the number of pixels that the filer spans, in filter space (the | 81 // Returns the number of pixels that the filer spans, in filter space (the |
| 79 // destination image). | 82 // destination image). |
| 80 float GetFilterSupport(float scale) { | 83 float GetFilterSupport(float scale) { |
| 81 switch (method_) { | 84 switch (method_) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 return EvalLanczos(3, pos); | 119 return EvalLanczos(3, pos); |
| 117 default: | 120 default: |
| 118 NOTREACHED(); | 121 NOTREACHED(); |
| 119 return 0; | 122 return 0; |
| 120 } | 123 } |
| 121 } | 124 } |
| 122 | 125 |
| 123 ImageOperations::ResizeMethod method_; | 126 ImageOperations::ResizeMethod method_; |
| 124 | 127 |
| 125 // Subset of source the filters will touch. | 128 // Subset of source the filters will touch. |
| 126 Rect src_depend_; | 129 gfx::Rect src_depend_; |
| 127 | 130 |
| 128 // Size of the filter support on one side only in the destination space. | 131 // Size of the filter support on one side only in the destination space. |
| 129 // See GetFilterSupport. | 132 // See GetFilterSupport. |
| 130 float x_filter_support_; | 133 float x_filter_support_; |
| 131 float y_filter_support_; | 134 float y_filter_support_; |
| 132 | 135 |
| 133 // Subset of scaled destination bitmap to compute. | 136 // Subset of scaled destination bitmap to compute. |
| 134 Rect out_bounds_; | 137 gfx::Rect out_bounds_; |
| 135 | 138 |
| 136 ConvolusionFilter1D x_filter_; | 139 ConvolusionFilter1D x_filter_; |
| 137 ConvolusionFilter1D y_filter_; | 140 ConvolusionFilter1D y_filter_; |
| 138 | 141 |
| 139 DISALLOW_EVIL_CONSTRUCTORS(ResizeFilter); | 142 DISALLOW_EVIL_CONSTRUCTORS(ResizeFilter); |
| 140 }; | 143 }; |
| 141 | 144 |
| 142 ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, | 145 ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, |
| 143 const Size& src_full_size, | 146 int src_full_width, int src_full_height, |
| 144 const Size& dest_size, | 147 int dest_width, int dest_height, |
| 145 const Rect& dest_subset) | 148 const gfx::Rect& dest_subset) |
| 146 : method_(method), | 149 : method_(method), |
| 147 out_bounds_(dest_subset) { | 150 out_bounds_(dest_subset) { |
| 148 float scale_x = static_cast<float>(dest_size.width()) / | 151 float scale_x = static_cast<float>(dest_width) / |
| 149 static_cast<float>(src_full_size.width()); | 152 static_cast<float>(src_full_width); |
| 150 float scale_y = static_cast<float>(dest_size.height()) / | 153 float scale_y = static_cast<float>(dest_height) / |
| 151 static_cast<float>(src_full_size.height()); | 154 static_cast<float>(src_full_height); |
| 152 | 155 |
| 153 x_filter_support_ = GetFilterSupport(scale_x); | 156 x_filter_support_ = GetFilterSupport(scale_x); |
| 154 y_filter_support_ = GetFilterSupport(scale_y); | 157 y_filter_support_ = GetFilterSupport(scale_y); |
| 155 | 158 |
| 156 gfx::Rect src_full(0, 0, src_full_size.width(), src_full_size.height()); | 159 gfx::Rect src_full(0, 0, src_full_width, src_full_height); |
| 157 gfx::Rect dest_full(0, 0, | 160 gfx::Rect dest_full(0, 0, |
| 158 static_cast<int>(src_full_size.width() * scale_x + 0.5), | 161 static_cast<int>(src_full_width * scale_x + 0.5), |
| 159 static_cast<int>(src_full_size.height() * scale_y + 0.5)); | 162 static_cast<int>(src_full_height * scale_y + 0.5)); |
| 160 | 163 |
| 161 // Support of the filter in source space. | 164 // Support of the filter in source space. |
| 162 float src_x_support = x_filter_support_ / scale_x; | 165 float src_x_support = x_filter_support_ / scale_x; |
| 163 float src_y_support = y_filter_support_ / scale_y; | 166 float src_y_support = y_filter_support_ / scale_y; |
| 164 | 167 |
| 165 ComputeFilters(src_full_size.width(), dest_subset.x(), dest_subset.width(), | 168 ComputeFilters(src_full_width, dest_subset.x(), dest_subset.width(), |
| 166 scale_x, src_x_support, &x_filter_); | 169 scale_x, src_x_support, &x_filter_); |
| 167 ComputeFilters(src_full_size.height(), dest_subset.y(), dest_subset.height(), | 170 ComputeFilters(src_full_height, dest_subset.y(), dest_subset.height(), |
| 168 scale_y, src_y_support, &y_filter_); | 171 scale_y, src_y_support, &y_filter_); |
| 169 } | 172 } |
| 170 | 173 |
| 171 void ResizeFilter::ComputeFilters(int src_size, | 174 void ResizeFilter::ComputeFilters(int src_size, |
| 172 int dest_subset_lo, int dest_subset_size, | 175 int dest_subset_lo, int dest_subset_size, |
| 173 float scale, float src_support, | 176 float scale, float src_support, |
| 174 ConvolusionFilter1D* output) { | 177 ConvolusionFilter1D* output) { |
| 175 int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) | 178 int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) |
| 176 | 179 |
| 177 // When we're doing a magnification, the scale will be larger than one. This | 180 // When we're doing a magnification, the scale will be larger than one. This |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 } | 250 } |
| 248 } | 251 } |
| 249 | 252 |
| 250 } // namespace | 253 } // namespace |
| 251 | 254 |
| 252 // Resize ---------------------------------------------------------------------- | 255 // Resize ---------------------------------------------------------------------- |
| 253 | 256 |
| 254 // static | 257 // static |
| 255 SkBitmap ImageOperations::Resize(const SkBitmap& source, | 258 SkBitmap ImageOperations::Resize(const SkBitmap& source, |
| 256 ResizeMethod method, | 259 ResizeMethod method, |
| 257 const Size& dest_size, | 260 int dest_width, int dest_height, |
| 258 const Rect& dest_subset) { | 261 const gfx::Rect& dest_subset) { |
| 259 DCHECK(Rect(dest_size.width(), dest_size.height()).Contains(dest_subset)) << | 262 DCHECK(gfx::Rect(dest_width, dest_height).Contains(dest_subset)) << |
| 260 "The supplied subset does not fall within the destination image."; | 263 "The supplied subset does not fall within the destination image."; |
| 261 | 264 |
| 262 // 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 |
| 263 // return empty | 266 // return empty |
| 264 if (source.width() < 1 || source.height() < 1 || | 267 if (source.width() < 1 || source.height() < 1 || |
| 265 dest_size.width() < 1 || dest_size.height() < 1) | 268 dest_width < 1 || dest_height < 1) |
| 266 return SkBitmap(); | 269 return SkBitmap(); |
| 267 | 270 |
| 268 SkAutoLockPixels locker(source); | 271 SkAutoLockPixels locker(source); |
| 269 | 272 |
| 270 ResizeFilter filter(method, Size(source.width(), source.height()), | 273 ResizeFilter filter(method, source.width(), source.height(), |
| 271 dest_size, dest_subset); | 274 dest_width, dest_height, dest_subset); |
| 272 | 275 |
| 273 // Get a source bitmap encompassing this touched area. We construct the | 276 // Get a source bitmap encompassing this touched area. We construct the |
| 274 // offsets and row strides such that it looks like a new bitmap, while | 277 // offsets and row strides such that it looks like a new bitmap, while |
| 275 // referring to the old data. | 278 // referring to the old data. |
| 276 const uint8* source_subset = | 279 const uint8* source_subset = |
| 277 reinterpret_cast<const uint8*>(source.getPixels()); | 280 reinterpret_cast<const uint8*>(source.getPixels()); |
| 278 | 281 |
| 279 // Convolve into the result. | 282 // Convolve into the result. |
| 280 SkBitmap result; | 283 SkBitmap result; |
| 281 result.setConfig(SkBitmap::kARGB_8888_Config, | 284 result.setConfig(SkBitmap::kARGB_8888_Config, |
| 282 dest_subset.width(), dest_subset.height()); | 285 dest_subset.width(), dest_subset.height()); |
| 283 result.allocPixels(); | 286 result.allocPixels(); |
| 284 BGRAConvolve2D(source_subset, static_cast<int>(source.rowBytes()), | 287 BGRAConvolve2D(source_subset, static_cast<int>(source.rowBytes()), |
| 285 !source.isOpaque(), filter.x_filter(), filter.y_filter(), | 288 !source.isOpaque(), filter.x_filter(), filter.y_filter(), |
| 286 static_cast<unsigned char*>(result.getPixels())); | 289 static_cast<unsigned char*>(result.getPixels())); |
| 287 | 290 |
| 288 // Preserve the "opaque" flag for use as an optimization later. | 291 // Preserve the "opaque" flag for use as an optimization later. |
| 289 result.setIsOpaque(source.isOpaque()); | 292 result.setIsOpaque(source.isOpaque()); |
| 290 | 293 |
| 291 return result; | 294 return result; |
| 292 } | 295 } |
| 293 | 296 |
| 294 // static | 297 // static |
| 295 SkBitmap ImageOperations::Resize(const SkBitmap& source, | 298 SkBitmap ImageOperations::Resize(const SkBitmap& source, |
| 296 ResizeMethod method, | 299 ResizeMethod method, |
| 297 const Size& dest_size) { | 300 int dest_width, int dest_height) { |
| 298 Rect dest_subset(0, 0, dest_size.width(), dest_size.height()); | 301 gfx::Rect dest_subset(0, 0, dest_width, dest_height); |
| 299 return Resize(source, method, dest_size, dest_subset); | 302 return Resize(source, method, dest_width, dest_height, dest_subset); |
| 300 } | 303 } |
| 301 | 304 |
| 302 // static | 305 // static |
| 303 SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, | 306 SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, |
| 304 const SkBitmap& second, | 307 const SkBitmap& second, |
| 305 double alpha) { | 308 double alpha) { |
| 306 DCHECK(alpha <= 1 && alpha >= 0); | 309 DCHECK(alpha <= 1 && alpha >= 0); |
| 307 DCHECK(first.width() == second.width()); | 310 DCHECK(first.width() == second.width()); |
| 308 DCHECK(first.height() == second.height()); | 311 DCHECK(first.height() == second.height()); |
| 309 DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); | 312 DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 SkColorGetB(first_pixel) * first_alpha + | 354 SkColorGetB(first_pixel) * first_alpha + |
| 352 SkColorGetB(second_pixel) * alpha); | 355 SkColorGetB(second_pixel) * alpha); |
| 353 | 356 |
| 354 dst_row[x] = SkColorSetARGB(a, r, g, b); | 357 dst_row[x] = SkColorSetARGB(a, r, g, b); |
| 355 } | 358 } |
| 356 } | 359 } |
| 357 | 360 |
| 358 return blended; | 361 return blended; |
| 359 } | 362 } |
| 360 | 363 |
| 361 } // namespace gfx | 364 } // namespace skia |
| 362 | 365 |
| OLD | NEW |