UIScrollview - 模糊效果 iOS

Posted

技术标签:

【中文标题】UIScrollview - 模糊效果 iOS【英文标题】:UIScrollview - Blurry effects iOS 【发布时间】:2012-09-20 02:51:29 【问题描述】:

我有分页 UIScrollview。 UIScrollview 是用户选择的选项。我应该模糊那些不在滚动视图框架内的页面。对此有何建议?这是实现的 UIScrollview 的screenshot。低 alpha 分量的黑框将被其他页面上的模糊效果替换。

【问题讨论】:

你试过什么?显然,通过使用 CALayer 标记来标记这个问题,您已经完成了一些类似的实现。 dimzzy.com/blog/2010/11/blur-effect-for-uiview 我看到了这个链接。然而,要在那些不在框架内的***上添加模糊效果,我需要在滚动视图顶部和框架外添加模糊效果。这将不允许我滚动 UIScrollview,因为它位于模糊的 UIView 下方。 【参考方案1】:

我通过UIImage 上的一个类别实现了这一目标...

.h 文件:

#import <Foundation/Foundation.h>

@interface UIImage (StackBlur) 
    - (UIImage*) stackBlur:(NSUInteger)radius;
    - (UIImage *) normalize ;

@end

.m 文件:

#import "UIImage+StackBlur.h"

@implementation  UIImage (StackBlur)    

// Stackblur algorithm
// from
// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php
// by  Mario Klingemann

- (UIImage*) stackBlur:(NSUInteger)inradius

    int radius=inradius; // Transform unsigned into signed for further operations

    if (radius<1)
        return self;
    
    // Suggestion xidew to prevent crash if size is null
    if (CGSizeEqualToSize(self.size, CGSizeZero)) 
        return self;
    

    //  return [other applyBlendFilter:filterOverlay  other:self context:nil];
    // First get the image into your data buffer
    CGImageRef inImage = self.CGImage;
    int nbPerCompt=CGImageGetBitsPerPixel(inImage);
    if(nbPerCompt!=32)
        UIImage *tmpImage=[self normalize];
        inImage=tmpImage.CGImage;
    
    CFDataRef m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));  
    UInt8 * m_PixelBuf=malloc(CFDataGetLength(m_DataRef));
    CFDataGetBytes(m_DataRef,
                   CFRangeMake(0,CFDataGetLength(m_DataRef)) ,
                   m_PixelBuf);

    CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf,  
                                             CGImageGetWidth(inImage),  
                                             CGImageGetHeight(inImage),  
                                             CGImageGetBitsPerComponent(inImage),
                                             CGImageGetBytesPerRow(inImage),  
                                             CGImageGetColorSpace(inImage),  
                                             CGImageGetBitmapInfo(inImage) 
                                             ); 


    int w=CGImageGetWidth(inImage);
    int h=CGImageGetHeight(inImage);
    int wm=w-1;
    int hm=h-1;
    int wh=w*h;
    int div=radius+radius+1;

    int *r=malloc(wh*sizeof(int));
    int *g=malloc(wh*sizeof(int));
    int *b=malloc(wh*sizeof(int));
    memset(r,0,wh*sizeof(int));
    memset(g,0,wh*sizeof(int));
    memset(b,0,wh*sizeof(int));
    int rsum,gsum,bsum,x,y,i,p,yp,yi,yw;
    int *vmin = malloc(sizeof(int)*MAX(w,h));
    memset(vmin,0,sizeof(int)*MAX(w,h));
    int divsum=(div+1)>>1;
    divsum*=divsum;
    int *dv=malloc(sizeof(int)*(256*divsum));
    for (i=0;i<256*divsum;i++)
        dv[i]=(i/divsum);
    

    yw=yi=0;

    int *stack=malloc(sizeof(int)*(div*3));
    int stackpointer;
    int stackstart;
    int *sir;
    int rbs;
    int r1=radius+1;
    int routsum,goutsum,boutsum;
    int rinsum,ginsum,binsum;
    memset(stack,0,sizeof(int)*div*3);

    for (y=0;y<h;y++)
        rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;

        for(int i=-radius;i<=radius;i++)
            sir=&stack[(i+radius)*3];
            /*          p=m_PixelBuf[yi+MIN(wm,MAX(i,0))];
             sir[0]=(p & 0xff0000)>>16;
             sir[1]=(p & 0x00ff00)>>8;
             sir[2]=(p & 0x0000ff);
             */
            int offset=(yi+MIN(wm,MAX(i,0)))*4;
            sir[0]=m_PixelBuf[offset];
            sir[1]=m_PixelBuf[offset+1];
            sir[2]=m_PixelBuf[offset+2];

            rbs=r1-abs(i);
            rsum+=sir[0]*rbs;
            gsum+=sir[1]*rbs;
            bsum+=sir[2]*rbs;
            if (i>0)
                rinsum+=sir[0];
                ginsum+=sir[1];
                binsum+=sir[2];
             else 
                routsum+=sir[0];
                goutsum+=sir[1];
                boutsum+=sir[2];
            
        
        stackpointer=radius;


        for (x=0;x<w;x++)
            r[yi]=dv[rsum];
            g[yi]=dv[gsum];
            b[yi]=dv[bsum];

            rsum-=routsum;
            gsum-=goutsum;
            bsum-=boutsum;

            stackstart=stackpointer-radius+div;
            sir=&stack[(stackstart%div)*3];

            routsum-=sir[0];
            goutsum-=sir[1];
            boutsum-=sir[2];

            if(y==0)
                vmin[x]=MIN(x+radius+1,wm);
            

            /*          p=m_PixelBuf[yw+vmin[x]];

             sir[0]=(p & 0xff0000)>>16;
             sir[1]=(p & 0x00ff00)>>8;
             sir[2]=(p & 0x0000ff);
             */
            int offset=(yw+vmin[x])*4;
            sir[0]=m_PixelBuf[offset];
            sir[1]=m_PixelBuf[offset+1];
            sir[2]=m_PixelBuf[offset+2];
            rinsum+=sir[0];
            ginsum+=sir[1];
            binsum+=sir[2];

            rsum+=rinsum;
            gsum+=ginsum;
            bsum+=binsum;

            stackpointer=(stackpointer+1)%div;
            sir=&stack[((stackpointer)%div)*3];

            routsum+=sir[0];
            goutsum+=sir[1];
            boutsum+=sir[2];

            rinsum-=sir[0];
            ginsum-=sir[1];
            binsum-=sir[2];

            yi++;
        
        yw+=w;
    
    for (x=0;x<w;x++)
        rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0;
        yp=-radius*w;
        for(i=-radius;i<=radius;i++)
            yi=MAX(0,yp)+x;

            sir=&stack[(i+radius)*3];

            sir[0]=r[yi];
            sir[1]=g[yi];
            sir[2]=b[yi];

            rbs=r1-abs(i);

            rsum+=r[yi]*rbs;
            gsum+=g[yi]*rbs;
            bsum+=b[yi]*rbs;

            if (i>0)
                rinsum+=sir[0];
                ginsum+=sir[1];
                binsum+=sir[2];
             else 
                routsum+=sir[0];
                goutsum+=sir[1];
                boutsum+=sir[2];
            

            if(i<hm)
                yp+=w;
            
        
        yi=x;
        stackpointer=radius;
        for (y=0;y<h;y++)
            //          m_PixelBuf[yi]=0xff000000 | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
            int offset=yi*4;
            m_PixelBuf[offset]=dv[rsum];
            m_PixelBuf[offset+1]=dv[gsum];
            m_PixelBuf[offset+2]=dv[bsum];
            rsum-=routsum;
            gsum-=goutsum;
            bsum-=boutsum;

            stackstart=stackpointer-radius+div;
            sir=&stack[(stackstart%div)*3];

            routsum-=sir[0];
            goutsum-=sir[1];
            boutsum-=sir[2];

            if(x==0)
                vmin[y]=MIN(y+r1,hm)*w;
            
            p=x+vmin[y];

            sir[0]=r[p];
            sir[1]=g[p];
            sir[2]=b[p];

            rinsum+=sir[0];
            ginsum+=sir[1];
            binsum+=sir[2];

            rsum+=rinsum;
            gsum+=ginsum;
            bsum+=binsum;

            stackpointer=(stackpointer+1)%div;
            sir=&stack[(stackpointer)*3];

            routsum+=sir[0];
            goutsum+=sir[1];
            boutsum+=sir[2];

            rinsum-=sir[0];
            ginsum-=sir[1];
            binsum-=sir[2];

            yi+=w;
        
    
    free(r);
    free(g);
    free(b);
    free(vmin);
    free(dv);
    free(stack);
    CGImageRef imageRef = CGBitmapContextCreateImage(ctx);  
    CGContextRelease(ctx);  

    UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);   
    CFRelease(m_DataRef);
    free(m_PixelBuf);
    return finalImage;



- (UIImage *) normalize 

    CGColorSpaceRef genericColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef thumbBitmapCtxt = CGBitmapContextCreate(NULL,

                                                         self.size.width,
                                                         self.size.height,
                                                         8, (4 * self.size.width),
                                                         genericColorSpace,
                                                         kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(genericColorSpace);
    CGContextSetInterpolationQuality(thumbBitmapCtxt, kCGInterpolationDefault);
    CGRect destRect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextDrawImage(thumbBitmapCtxt, destRect, self.CGImage);
    CGImageRef tmpThumbImage = CGBitmapContextCreateImage(thumbBitmapCtxt);
    CGContextRelease(thumbBitmapCtxt);   
    UIImage *result = [UIImage imageWithCGImage:tmpThumbImage];
    CGImageRelease(tmpThumbImage);

    return result;   


@end

使用此代码模糊图像...

self.rawImage.image=[self.rawImage.image stackBlur:10.0f];

【讨论】:

不仅仅是模糊。我需要模糊那些不在滚动视图框架内的内容。这可能吗?

以上是关于UIScrollview - 模糊效果 iOS的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView可滚动内容大小模糊

具有水平缩放的 UIScrollView - 在子视图中绘制的贝塞尔路径模糊

利用递归 实现UIScrollView无限滚动的效果

在 UIScrollView 中滚动图像时添加视差效果

UIScrollView 缩放抖动效果

使用UIScrollView和UIPageControl做一个能够用手势来切换图片的效果