void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, unsigned int width, SkScalar sigma) { unsigned int profile_size = SkScalarCeilToInt(6*sigma); SkAutoTMalloc<uint8_t> horizontalScanline(width); unsigned int sw = width - profile_size; // nearest odd number less than the profile size represents the center // of the (2x scaled) profile int center = ( profile_size & ~1 ) - 1; int w = sw - center; for (unsigned int x = 0 ; x < width ; ++x) { if (profile_size <= sw) { pixels[x] = ProfileLookup(profile, x, width, w); } else { float span = float(sw)/(2*sigma); float giX = 1.5f - (x+.5f)/(2*sigma); pixels[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); } } }
void SkBlurMask::ComputeBlurProfile(uint8_t* profile, int size, SkScalar sigma) { SkASSERT(SkScalarCeilToInt(6*sigma) == size); int center = size >> 1; float invr = 1.f/(2*sigma); profile[0] = 255; for (int x = 1 ; x < size ; ++x) { float scaled_x = (center - x - .5f) * invr; float gi = gaussianIntegral(scaled_x); profile[x] = 255 - (uint8_t) (255.f * gi); } }
static void compute_profile(SkScalar radius, unsigned int **profile_out) { int size = compute_profile_size(radius); int center = size >> 1; unsigned int *profile = SkNEW_ARRAY(unsigned int, size); float invr = 1.f/radius; profile[0] = 255; for (int x = 1 ; x < size ; ++x) { float scaled_x = (center - x - .5f) * invr; float gi = gaussianIntegral(scaled_x); profile[x] = 255 - (uint8_t) (255.f * gi); } *profile_out = profile; }
uint8_t* SkBlurMask::ComputeBlurProfile(SkScalar sigma) { int size = SkScalarCeilToInt(6*sigma); int center = size >> 1; uint8_t* profile = new uint8_t[size]; float invr = 1.f/(2*sigma); profile[0] = 255; for (int x = 1 ; x < size ; ++x) { float scaled_x = (center - x - .5f) * invr; float gi = gaussianIntegral(scaled_x); profile[x] = 255 - (uint8_t) (255.f * gi); } return profile; }
bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src, SkScalar provided_radius, Style style, SkIPoint *margin, SkMask::CreateMode createMode) { int profile_size; float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor)); // adjust blur radius to match interpretation from boxfilter code radius = (radius + .5f) * 2.f; profile_size = compute_profile_size(radius); int pad = profile_size/2; if (margin) { margin->set( pad, pad ); } dst->fBounds.set(SkScalarRoundToInt(src.fLeft - pad), SkScalarRoundToInt(src.fTop - pad), SkScalarRoundToInt(src.fRight + pad), SkScalarRoundToInt(src.fBottom + pad)); dst->fRowBytes = dst->fBounds.width(); dst->fFormat = SkMask::kA8_Format; dst->fImage = NULL; int sw = SkScalarFloorToInt(src.width()); int sh = SkScalarFloorToInt(src.height()); if (createMode == SkMask::kJustComputeBounds_CreateMode) { if (style == kInner_Style) { dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } return true; } unsigned int *profile = NULL; compute_profile(radius, &profile); SkAutoTDeleteArray<unsigned int> ada(profile); size_t dstSize = dst->computeImageSize(); if (0 == dstSize) { return false; // too big to allocate, abort } uint8_t* dp = SkMask::AllocImage(dstSize); dst->fImage = dp; int dstHeight = dst->fBounds.height(); int dstWidth = dst->fBounds.width(); // nearest odd number less than the profile size represents the center // of the (2x scaled) profile int center = ( profile_size & ~1 ) - 1; int w = sw - center; int h = sh - center; uint8_t *outptr = dp; SkAutoTMalloc<uint8_t> horizontalScanline(dstWidth); for (int x = 0 ; x < dstWidth ; ++x) { if (profile_size <= sw) { horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w); } else { float span = float(sw)/radius; float giX = 1.5f - (x+.5f)/radius; horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span))); } } for (int y = 0 ; y < dstHeight ; ++y) { unsigned int profile_y; if (profile_size <= sh) { profile_y = profile_lookup(profile, y, dstHeight, h); } else { float span = float(sh)/radius; float giY = 1.5f - (y+.5f)/radius; profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span))); } for (int x = 0 ; x < dstWidth ; x++) { unsigned int maskval = SkMulDiv255Round(horizontalScanline[x], profile_y); *(outptr++) = maskval; } } if (style == kInner_Style) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = (size_t)(src.width() * src.height()); if (0 == srcSize) { return false; // too big to allocate, abort } dst->fImage = SkMask::AllocImage(srcSize); for (int y = 0 ; y < sh ; y++) { uint8_t *blur_scanline = dp + (y+pad)*dstWidth + pad; uint8_t *inner_scanline = dst->fImage + y*sw; memcpy(inner_scanline, blur_scanline, sw); } SkMask::FreeImage(dp); dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; } else if (style == kOuter_Style) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0, sw); } } else if (style == kSolid_Style) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0xff, sw); } } // normal and solid styles are the same for analytic rect blurs, so don't // need to handle solid specially. return true; }