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 |