diff options
author | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-03 01:11:58 +0000 |
---|---|---|
committer | brettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-03 01:11:58 +0000 |
commit | ae615162135445eb0b94365b1a1cfa511e7f4be4 (patch) | |
tree | a32c9ad049aa25b3c40038713d546c3521d3d20e /skia/ext/image_operations.cc | |
parent | 693f8e4af78b0bb38cb56cd913c8774c75b43067 (diff) | |
download | chromium_src-ae615162135445eb0b94365b1a1cfa511e7f4be4.zip chromium_src-ae615162135445eb0b94365b1a1cfa511e7f4be4.tar.gz chromium_src-ae615162135445eb0b94365b1a1cfa511e7f4be4.tar.bz2 |
Revert my skia file moves because of layout test failures.
Review URL: http://codereview.chromium.org/12892
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6266 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ext/image_operations.cc')
-rw-r--r-- | skia/ext/image_operations.cc | 366 |
1 files changed, 0 insertions, 366 deletions
diff --git a/skia/ext/image_operations.cc b/skia/ext/image_operations.cc deleted file mode 100644 index 9eab6e5..0000000 --- a/skia/ext/image_operations.cc +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -#define _USE_MATH_DEFINES -#include <cmath> -#include <limits> -#include <vector> - -#include "skia/ext/image_operations.h" - -#include "base/gfx/rect.h" -#include "base/gfx/size.h" -#include "base/logging.h" -#include "base/stack_container.h" -#include "skia/ext/convolver.h" -#include "SkBitmap.h" - -// TODO(brettw) this should be removed when the base/gfx dependencies are -// removed. -using namespace gfx; - -namespace skia { - -namespace { - -// Returns the ceiling/floor as an integer. -inline int CeilInt(float val) { - return static_cast<int>(ceil(val)); -} -inline int FloorInt(float val) { - return static_cast<int>(floor(val)); -} - -// Filter function computation ------------------------------------------------- - -// Evaluates the box filter, which goes from -0.5 to +0.5. -float EvalBox(float x) { - return (x >= -0.5f && x < 0.5f) ? 1.0f : 0.0f; -} - -// Evaluates the Lanczos filter of the given filter size window for the given -// position. -// -// |filter_size| is the width of the filter (the "window"), outside of which -// the value of the function is 0. Inside of the window, the value is the -// normalized sinc function: -// lanczos(x) = sinc(x) * sinc(x / filter_size); -// where -// sinc(x) = sin(pi*x) / (pi*x); -float EvalLanczos(int filter_size, float x) { - if (x <= -filter_size || x >= filter_size) - return 0.0f; // Outside of the window. - if (x > -std::numeric_limits<float>::epsilon() && - x < std::numeric_limits<float>::epsilon()) - return 1.0f; // Special case the discontinuity at the origin. - float xpi = x * static_cast<float>(M_PI); - return (sin(xpi) / xpi) * // sinc(x) - sin(xpi / filter_size) / (xpi / filter_size); // sinc(x/filter_size) -} - -// ResizeFilter ---------------------------------------------------------------- - -// Encapsulates computation and storage of the filters required for one complete -// resize operation. -class ResizeFilter { - public: - ResizeFilter(ImageOperations::ResizeMethod method, - const Size& src_full_size, - const Size& dest_size, - const Rect& dest_subset); - - // Returns the bounds in the input bitmap of data that is used in the output. - // The filter offsets are within this rectangle. - const Rect& src_depend() { return src_depend_; } - - // Returns the filled filter values. - const ConvolusionFilter1D& x_filter() { return x_filter_; } - const ConvolusionFilter1D& y_filter() { return y_filter_; } - - private: - // Returns the number of pixels that the filer spans, in filter space (the - // destination image). - float GetFilterSupport(float scale) { - switch (method_) { - case ImageOperations::RESIZE_BOX: - // The box filter just scales with the image scaling. - return 0.5f; // Only want one side of the filter = /2. - case ImageOperations::RESIZE_LANCZOS3: - // The lanczos filter takes as much space in the source image in - // each direction as the size of the window = 3 for Lanczos3. - return 3.0f; - default: - NOTREACHED(); - return 1.0f; - } - } - - // Computes one set of filters either horizontally or vertically. The caller - // will specify the "min" and "max" rather than the bottom/top and - // right/bottom so that the same code can be re-used in each dimension. - // - // |src_depend_lo| and |src_depend_size| gives the range for the source - // depend rectangle (horizontally or vertically at the caller's discretion - // -- see above for what this means). - // - // Likewise, the range of destination values to compute and the scale factor - // for the transform is also specified. - void ComputeFilters(int src_size, - int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolusionFilter1D* output); - - // Computes the filter value given the coordinate in filter space. - inline float ComputeFilter(float pos) { - switch (method_) { - case ImageOperations::RESIZE_BOX: - return EvalBox(pos); - case ImageOperations::RESIZE_LANCZOS3: - return EvalLanczos(2, pos); - default: - NOTREACHED(); - return 0; - } - } - - ImageOperations::ResizeMethod method_; - - // Subset of source the filters will touch. - Rect src_depend_; - - // Size of the filter support on one side only in the destination space. - // See GetFilterSupport. - float x_filter_support_; - float y_filter_support_; - - // Subset of scaled destination bitmap to compute. - Rect out_bounds_; - - ConvolusionFilter1D x_filter_; - ConvolusionFilter1D y_filter_; - - DISALLOW_EVIL_CONSTRUCTORS(ResizeFilter); -}; - -ResizeFilter::ResizeFilter(ImageOperations::ResizeMethod method, - const Size& src_full_size, - const Size& dest_size, - const Rect& dest_subset) - : method_(method), - out_bounds_(dest_subset) { - float scale_x = static_cast<float>(dest_size.width()) / - static_cast<float>(src_full_size.width()); - float scale_y = static_cast<float>(dest_size.height()) / - static_cast<float>(src_full_size.height()); - - x_filter_support_ = GetFilterSupport(scale_x); - y_filter_support_ = GetFilterSupport(scale_y); - - gfx::Rect src_full(0, 0, src_full_size.width(), src_full_size.height()); - gfx::Rect dest_full(0, 0, - static_cast<int>(src_full_size.width() * scale_x + 0.5), - static_cast<int>(src_full_size.height() * scale_y + 0.5)); - - // Support of the filter in source space. - float src_x_support = x_filter_support_ / scale_x; - float src_y_support = y_filter_support_ / scale_y; - - ComputeFilters(src_full_size.width(), dest_subset.x(), dest_subset.width(), - scale_x, src_x_support, &x_filter_); - ComputeFilters(src_full_size.height(), dest_subset.y(), dest_subset.height(), - scale_y, src_y_support, &y_filter_); -} - -void ResizeFilter::ComputeFilters(int src_size, - int dest_subset_lo, int dest_subset_size, - float scale, float src_support, - ConvolusionFilter1D* output) { - int dest_subset_hi = dest_subset_lo + dest_subset_size; // [lo, hi) - - // When we're doing a magnification, the scale will be larger than one. This - // means the destination pixels are much smaller than the source pixels, and - // that the range covered by the filter won't necessarily cover any source - // pixel boundaries. Therefore, we use these clamped values (max of 1) for - // some computations. - float clamped_scale = std::min(1.0f, scale); - - // Speed up the divisions below by turning them into multiplies. - float inv_scale = 1.0f / scale; - - StackVector<float, 64> filter_values; - StackVector<int16, 64> fixed_filter_values; - - // Loop over all pixels in the output range. We will generate one set of - // filter values for each one. Those values will tell us how to blend the - // source pixels to compute the destination pixel. - for (int dest_subset_i = dest_subset_lo; dest_subset_i < dest_subset_hi; - dest_subset_i++) { - // Reset the arrays. We don't declare them inside so they can re-use the - // same malloc-ed buffer. - filter_values->clear(); - fixed_filter_values->clear(); - - // This is the pixel in the source directly under the pixel in the dest. - float src_pixel = dest_subset_i * inv_scale; - - // Compute the (inclusive) range of source pixels the filter covers. - int src_begin = std::max(0, FloorInt(src_pixel - src_support)); - int src_end = std::min(src_size - 1, CeilInt(src_pixel + src_support)); - - // Compute the unnormalized filter value at each location of the source - // it covers. - float filter_sum = 0.0f; // Sub of the filter values for normalizing. - for (int cur_filter_pixel = src_begin; cur_filter_pixel <= src_end; - cur_filter_pixel++) { - // Distance from the center of the filter, this is the filter coordinate - // in source space. - float src_filter_pos = cur_filter_pixel - src_pixel; - - // Since the filter really exists in dest space, map it there. - float dest_filter_pos = src_filter_pos * clamped_scale; - - // Compute the filter value at that location. - float filter_value = ComputeFilter(dest_filter_pos); - filter_values->push_back(filter_value); - - filter_sum += filter_value; - } - DCHECK(!filter_values->empty()) << "We should always get a filter!"; - - // The filter must be normalized so that we don't affect the brightness of - // the image. Convert to normalized fixed point. - int16 fixed_sum = 0; - for (size_t i = 0; i < filter_values->size(); i++) { - int16 cur_fixed = output->FloatToFixed(filter_values[i] / filter_sum); - fixed_sum += cur_fixed; - fixed_filter_values->push_back(cur_fixed); - } - - // The conversion to fixed point will leave some rounding errors, which - // we add back in to avoid affecting the brightness of the image. We - // arbitrarily add this to the center of the filter array (this won't always - // be the center of the filter function since it could get clipped on the - // edges, but it doesn't matter enough to worry about that case). - int16 leftovers = output->FloatToFixed(1.0f) - fixed_sum; - fixed_filter_values[fixed_filter_values->size() / 2] += leftovers; - - // Now it's ready to go. - output->AddFilter(src_begin, &fixed_filter_values[0], - static_cast<int>(fixed_filter_values->size())); - } -} - -} // namespace - -// Resize ---------------------------------------------------------------------- - -// static -SkBitmap ImageOperations::Resize(const SkBitmap& source, - ResizeMethod method, - const Size& dest_size, - const Rect& dest_subset) { - DCHECK(Rect(dest_size.width(), dest_size.height()).Contains(dest_subset)) << - "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 - if (source.width() < 1 || source.height() < 1 || - dest_size.width() < 1 || dest_size.height() < 1) - return SkBitmap(); - - SkAutoLockPixels locker(source); - - ResizeFilter filter(method, Size(source.width(), source.height()), - dest_size, dest_subset); - - // Get a source bitmap encompassing this touched area. We construct the - // offsets and row strides such that it looks like a new bitmap, while - // referring to the old data. - const uint8* source_subset = - reinterpret_cast<const uint8*>(source.getPixels()); - - // Convolve into the result. - SkBitmap result; - result.setConfig(SkBitmap::kARGB_8888_Config, - dest_subset.width(), dest_subset.height()); - result.allocPixels(); - BGRAConvolve2D(source_subset, static_cast<int>(source.rowBytes()), - !source.isOpaque(), filter.x_filter(), filter.y_filter(), - static_cast<unsigned char*>(result.getPixels())); - - // Preserve the "opaque" flag for use as an optimization later. - result.setIsOpaque(source.isOpaque()); - - return result; -} - -// static -SkBitmap ImageOperations::Resize(const SkBitmap& source, - ResizeMethod method, - const Size& dest_size) { - Rect dest_subset(0, 0, dest_size.width(), dest_size.height()); - return Resize(source, method, dest_size, dest_subset); -} - -// static -SkBitmap ImageOperations::CreateBlendedBitmap(const SkBitmap& first, - const SkBitmap& second, - double alpha) { - DCHECK(alpha <= 1 && alpha >= 0); - DCHECK(first.width() == second.width()); - DCHECK(first.height() == second.height()); - DCHECK(first.bytesPerPixel() == second.bytesPerPixel()); - DCHECK(first.config() == SkBitmap::kARGB_8888_Config); - - // 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) { - return first; - } else if (alpha > alpha_max) { - return second; - } - - SkAutoLockPixels lock_first(first); - SkAutoLockPixels lock_second(second); - - SkBitmap blended; - blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), - first.height(), 0); - blended.allocPixels(); - blended.eraseARGB(0, 0, 0, 0); - - double first_alpha = 1 - alpha; - - for (int y = 0; y < first.height(); y++) { - uint32* first_row = first.getAddr32(0, y); - uint32* second_row = second.getAddr32(0, y); - uint32* dst_row = blended.getAddr32(0, y); - - for (int x = 0; x < first.width(); x++) { - uint32 first_pixel = first_row[x]; - uint32 second_pixel = second_row[x]; - - int a = static_cast<int>( - SkColorGetA(first_pixel) * first_alpha + - SkColorGetA(second_pixel) * alpha); - int r = static_cast<int>( - SkColorGetR(first_pixel) * first_alpha + - SkColorGetR(second_pixel) * alpha); - int g = static_cast<int>( - SkColorGetG(first_pixel) * first_alpha + - SkColorGetG(second_pixel) * alpha); - int b = static_cast<int>( - SkColorGetB(first_pixel) * first_alpha + - SkColorGetB(second_pixel) * alpha); - - dst_row[x] = SkColorSetARGB(a, r, g, b); - } - } - - return blended; -} - -} // namespace skia - |