Blur specific part of an image (rectangular, circular)?

I want to blur image rectangular or circular. After googling, I found that it is easy to blur whole image but it difficult to blur specific part of image (rectangular, circular). so how it is possible ???

Thanks in advance


Solution 1:

enter image description here

Just set your UIImageView property name as "imageView" and add the following four methods with the same sequence in your implementation file. Also, set your ImageView Mode to 'Redraw'. Add UIImage Category for the blur effect as given or use any custom class, it will work for you.

Method 1 - Cropping the Image

#pragma mark - Cropping the Image 

- (UIImage *)croppIngimageByImageName:(UIImage *)imageToCrop toRect:(CGRect)rect{

    CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);    
    UIImage *cropped = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return cropped;   


}

Method 2 - Merge the two Images

#pragma mark - Marge two Images 

- (UIImage *) addImageToImage:(UIImage *)img withImage2:(UIImage *)img2 andRect:(CGRect)cropRect{

    CGSize size = CGSizeMake(imageView.image.size.width, imageView.image.size.height);
    UIGraphicsBeginImageContext(size);

    CGPoint pointImg1 = CGPointMake(0,0);
    [img drawAtPoint:pointImg1]; 

    CGPoint pointImg2 = cropRect.origin;
    [img2 drawAtPoint: pointImg2];

    UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return result;
}

Method 3 - RoundRect the Image

#pragma mark - RoundRect the Image

- (UIImage *)roundedRectImageFromImage:(UIImage *)image withRadious:(CGFloat)radious {

    if(radious == 0.0f)
        return image;

    if( image != nil) {

        CGFloat imageWidth = image.size.width;
        CGFloat imageHeight = image.size.height;

        CGRect rect = CGRectMake(0.0f, 0.0f, imageWidth, imageHeight);
        UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
        const CGFloat scale = window.screen.scale;
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, scale);

        CGContextRef context = UIGraphicsGetCurrentContext();

        CGContextBeginPath(context);
        CGContextSaveGState(context);
        CGContextTranslateCTM (context, CGRectGetMinX(rect), CGRectGetMinY(rect));
        CGContextScaleCTM (context, radious, radious);

        CGFloat rectWidth = CGRectGetWidth (rect)/radious;
        CGFloat rectHeight = CGRectGetHeight (rect)/radious;

        CGContextMoveToPoint(context, rectWidth, rectHeight/2.0f);
        CGContextAddArcToPoint(context, rectWidth, rectHeight, rectWidth/2.0f, rectHeight, radious);
        CGContextAddArcToPoint(context, 0.0f, rectHeight, 0.0f, rectHeight/2.0f, radious);
        CGContextAddArcToPoint(context, 0.0f, 0.0f, rectWidth/2.0f, 0.0f, radious);
        CGContextAddArcToPoint(context, rectWidth, 0.0f, rectWidth, rectHeight/2.0f, radious);
        CGContextRestoreGState(context);
        CGContextClosePath(context);
        CGContextClip(context);

        [image drawInRect:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)];

        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return newImage;
    } 
    return nil;
}

Method 4 - Touch Move

#pragma mark - Touch Methods

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {


    UIImage *croppedImg = nil;

    UITouch *touch = [touches anyObject];
    CGPoint currentPoint = [touch locationInView:self.imageView];

    double ratioW=imageView.image.size.width/imageView.frame.size.width ;

    double ratioH=imageView.image.size.height/imageView.frame.size.height;

    currentPoint.x *= ratioW;
    currentPoint.y *= ratioH;

    double circleSizeW = 30 * ratioW;
    double circleSizeH = 30 * ratioH;


    currentPoint.x = (currentPoint.x - circleSizeW/2<0)? 0 : currentPoint.x - circleSizeW/2;
    currentPoint.y = (currentPoint.y - circleSizeH/2<0)? 0 : currentPoint.y - circleSizeH/2;


    CGRect cropRect = CGRectMake(currentPoint.x , currentPoint.y,   circleSizeW,  circleSizeH);

    NSLog(@"x %0.0f, y %0.0f, width %0.0f, height %0.0f", cropRect.origin.x, cropRect.origin.y,   cropRect.size.width,  cropRect.size.height );

    croppedImg = [self croppIngimageByImageName:self.imageView.image toRect:cropRect];

    // Blur Effect 
    croppedImg = [croppedImg imageWithGaussianBlur9];

    // Contrast Effect 
    // croppedImg = [croppedImg imageWithContrast:50];



    croppedImg = [self roundedRectImageFromImage:croppedImg withRadious:4]; 

    imageView.image = [self addImageToImage:imageView.image withImage2:croppedImg andRect:cropRect];  
} 

UIImage Category Class

UIImage+ImageBlur.h

#import <UIKit/UIKit.h>

@interface UIImage (ImageBlur)

- (UIImage *)imageWithGaussianBlur9;

@end

UIImage+ImageBlur.m

#import "UIImage+ImageBlur.h"

@implementation UIImage (ImageBlur)

- (UIImage *)imageWithGaussianBlur9 {
    float weight[5] = {0.1270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162};
    // Blur horizontally
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[0]];
    for (int x = 1; x < 5; ++x) {
        [self drawInRect:CGRectMake(x, 0, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[x]];
        [self drawInRect:CGRectMake(-x, 0, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[x]];
    }
    UIImage *horizBlurredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    // Blur vertically
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [horizBlurredImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[0]];
    for (int y = 1; y < 5; ++y) {
        [horizBlurredImage drawInRect:CGRectMake(0, y, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[y]];
        [horizBlurredImage drawInRect:CGRectMake(0, -y, self.size.width, self.size.height) blendMode:kCGBlendModeNormal alpha:weight[y]];
    }
    UIImage *blurredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    //
    return blurredImage;
}

@end

happy coding....

Solution 2:

Add the following Pangesture in view or imageview

UIPanGestureRecognizer *panGesture=[[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(imageTaped:)];
[panGesture setMaximumNumberOfTouches:1];
[self.view addGestureRecognizer:panGesture];

The method for blur image

- (void)imageTaped:(UIPanGestureRecognizer *)gestureRecognizer
{

    CIContext *context = [CIContext contextWithOptions:nil];
    CGPoint touchLocation = [gestureRecognizer locationInView:self.imgviewMain];


    CGRect temp=CGRectMake(touchLocation.x-25, ((self.imgviewMain.frame.size.height-50) - touchLocation.y)+25, 50, 50);

    CIImage *inputImage0 = [[CIImage alloc] initWithImage:self.imgviewMain.image];

    CIImage *inputImage = [[CIImage alloc] initWithImage:[UIImage imageWithCGImage:[context createCGImage:inputImage0 fromRect:temp]]];
    CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [blurFilter setDefaults];
    [blurFilter setValue: inputImage forKey: @"inputImage"];
    [blurFilter setValue: [NSNumber numberWithFloat:0.1]
                  forKey:@"inputRadius"];


    CIImage *outputImage = [blurFilter valueForKey: @"outputImage"];
    UIImageView *imgtest=[[UIImageView alloc]init];

    imgtest.image=[UIImage imageWithCGImage:[context createCGImage:outputImage fromRect:outputImage.extent]];



    UIImage *image;

    UIImage *bottomImage = self.imgviewMain.image; 
          image = imgtest.image;    


    CGSize newSize = CGSizeMake(self.imgviewMain.frame.size.width, self.imgviewMain.frame.size.height);
    UIGraphicsBeginImageContext( newSize );

    [bottomImage drawInRect:CGRectMake(0,0,768,1024)];

    CGRect newRect2=CGRectMake(temp.origin.x,((self.imgviewMain.frame.size.height-50) - temp.origin.y), image.size.width, image.size.height);
    image=[self makeRoundedImage:image radius:10];

    [image drawInRect:newRect2 blendMode:kCGBlendModeNormal alpha:0.5];
     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    self.imgviewMain.image=newImage;
   }

RoundedImage Method

-(UIImage *)makeRoundedImage:(UIImage *) image
                      radius: (float) radius;
{
    CALayer *imageLayer = [CALayer layer];
    imageLayer.frame = CGRectMake(0, 0, image.size.width, image.size.height);
    imageLayer.contents = (id) image.CGImage;

    imageLayer.masksToBounds = YES;
    imageLayer.cornerRadius = radius;

    UIGraphicsBeginImageContext(image.size);
    [imageLayer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return roundedImage;
}

Solution 3:

I know I'm bit late for the party but it may help someone else who struggling to get this working.

I've recently needed to implement it and I couldn't find much info on internet about this specific topic ( specially how to get this working when dealing with different UIImageView's scale types such as Scale to Fill, Center and so on). So I've developed a small project that does exactly what you expect.

enter image description here

https://github.com/pauloubuntu/ios-blur-pan-gesture

Solution 4:

I managed to do an insta blur for OSX based projects. The drawing and graphics context management code can be different for OSX and iOS. Hope this helps other macOS devs wanting to do something similar!

Here we crop the image and overlay it on main imageview as user drags the mouse

- (void)mouseDragged:(NSEvent *)theEvent {

        NSPoint currentPoint = [self.view convertPoint:[theEvent locationInWindow] fromView:nil];
        NSPoint currentPointForOverLay = currentPoint;
        double ratioW=self.imageView.image.size.width/ self.imageView.frame.size.width ;
        double ratioH=self.imageView.image.size.height/self.imageView.frame.size.height;

        double circleSizeW = 30;   //Width and Height of Rect
        double circleSizeH = 30;

        currentPointBackup.x *= ratioW;
        currentPointBackup.y *= ratioH;

        CGRect overLayRect = CGRectMake(currentPointBackup.x , currentPointBackup.y,  circleSizeW  * ratioW,  circleSizeH * ratioH);

        CGRect cropRect = CGRectMake(currentPoint.x, currentPoint.y, circleSizeW, circleSizeH);

        //NSLog(@"x %0.0f, y %0.0f, width %0.0f, height %0.0f", cropRect.origin.x, cropRect.origin.y,   cropRect.size.width,  cropRect.size.height);

        //Logic to CROP Image on OSX 
        NSSize ratio = [(NSImageView*)self.imageExtractor.canvasController.contentView originalImageRatio];
        CGFloat x = cropRect.origin.x / ratio.width;
        CGFloat y = cropRect.origin.y / ratio.height;
        CGFloat w = cropRect.size.width / ratio.width;
        CGFloat h = cropRect.size.height / ratio.height;
        NSRect sourceFrame = NSMakeRect(x, y, w, h);
        NSRect targetFrame = NSMakeRect(0, 0, w*1.0f, h*1.0f);
        NSImage *targetImage = [[NSImage alloc] initWithSize:targetFrame.size];
        if(targetImage.size.width > 0 && targetFrame.size.height > 0) {
            [targetImage lockFocus];
            [[(NSImageView*)self.imageExtractor.canvasController.contentView originalImage] drawInRect:targetFrame fromRect:sourceFrame operation:NSCompositingOperationCopy fraction:1.0f];
            [targetImage unlockFocus];
        }
        //End CROP Image on OSX  

        //Apply filters
        NSData *data = targetImage.TIFFRepresentation;
        CIImage *croppedCIImage = [[CIImage alloc] initWithData:data];

        CIImage *filteredCIImage;
        if (self.filterTypeOnCanvas == BlurFilterMode)
        {
            CGFloat filterValue = self.blurSlider.floatValue;
            filteredCIImage = [filterManager getBlurredImage:croppedCIImage withAmount:filterValue];
        }
        else if (self.filterTypeOnCanvas == PixilateFilterMode)
        {
            CGFloat filterValue = self.pixillateSlider.floatValue;                
            filteredCIImage = [filterManager getPixellatedImage:croppedCIImage withAmount:filterValue];
        }

        CGImageRef cgimgRef = [context createCGImage:filteredCIImage
                                            fromRect:[croppedCIImage extent]];

        NSImage *blurredNSImage = [[NSImage alloc] initWithCGImage:cgimgRef size:cropRect.size];

        //Finally overlay the blurred image on main image
        NSImage *newImage = [imageUtils overlayImages:self.imageView.image overlayImage:blurredNSImage overLayRect:nsRect];

        self.imageView.image = newImage;
   }

OverLay Image Logic

- (NSImage *) overlayImages:(NSImage *)backgroundImage overlayImage:(NSImage *)overlayImage
           overLayRect:(NSRect)overLayRect
{
     NSImage *newImage = [[NSImage alloc] initWithSize:[backgroundImage size]];
     [newImage lockFocus];

     CGRect newImageRect = CGRectZero;
     newImageRect.size = [newImage size];

     [backgroundImage drawInRect:newImageRect];
     [overlayImage drawInRect:overLayRect];

     [newImage unlockFocus];

     return newImage;
}

Apply Filter

-(CIImage *)getBlurredImage:(CIImage *)img withAmount:(float)intensity {
    CIFilter *blurFilter = [CIFilter filterWithName:@"CIDiscBlur"];
    [blurFilter setValue:img forKey:kCIInputImageKey];
    [blurFilter setValue:@(intensity) forKey:@"inputRadius"];
    return blurFilter.outputImage; 
}

-(CIImage *)getPixellatedImage:(CIImage *)img withAmount:(float)scale
{
    CIFilter *pixilateFilter = [CIFilter filterWithName:@"CIPixellate"];
    [pixilateFilter setValue:img forKey:kCIInputImageKey];
    [pixilateFilter setValue:@(scale) forKey:@"inputScale"];

    return pixilateFilter.outputImage;
}