Pixelated layer on image in ios - ios

I need to add pixelated rectangular layer on UIImage which can be undo. Just like this..
I used this code but its not doing the same thing as i need
CALayer *maskLayer = [CALayer layer];
CALayer *mosaicLayer = [CALayer layer];
// Mask image ends with 0.15 opacity on both sides. Set the background color of the layer
// to the same value so the layer can extend the mask image.
mosaicLayer.contents = (id)[img CGImage];
mosaicLayer.frame = CGRectMake(0,0, img.size.width, img.size.height);
UIImage *maskImg = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"mask" ofType:#"png"]];
maskLayer.contents = (id)[maskImg CGImage];
maskLayer.frame = CGRectMake(100,150, maskImg.size.width, maskImg.size.height);
mosaicLayer.mask = maskLayer;
[imageView.layer addSublayer:mosaicLayer];
UIGraphicsBeginImageContext(imageView.layer.bounds.size);
[imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *saver = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
is there any built-in filter by apple for iOS? Please guide me Thanks

You can use GPUImage's GPUImagePixellateFilter https://github.com/BradLarson/GPUImage/blob/8811da388aed22e04ed54ca9a5a76791eeb40551/framework/Source/GPUImagePixellateFilter.h

We can use GPUImage framework but lot better is to use iOS own filters. easy coding :)
- (UIImage *)applyCIPixelateFilter:(UIImage*)fromImage withScale:(double)scale
{
/*
Makes an image blocky by mapping the image to colored squares whose color is defined by the replaced pixels.
Parameters
inputImage: A CIImage object whose display name is Image.
inputCenter: A CIVector object whose attribute type is CIAttributeTypePosition and whose display name is Center.
Default value: [150 150]
inputScale: An NSNumber object whose attribute type is CIAttributeTypeDistance and whose display name is Scale.
Default value: 8.00
*/
CIContext *context = [CIContext contextWithOptions:nil];
CIFilter *filter= [CIFilter filterWithName:#"CIPixellate"];
CIImage *inputImage = [[CIImage alloc] initWithImage:fromImage];
CIVector *vector = [CIVector vectorWithX:fromImage.size.width /2.0f Y:fromImage.size.height /2.0f];
[filter setDefaults];
[filter setValue:vector forKey:#"inputCenter"];
[filter setValue:[NSNumber numberWithDouble:scale] forKey:#"inputScale"];
[filter setValue:inputImage forKey:#"inputImage"];
CGImageRef cgiimage = [context createCGImage:filter.outputImage fromRect:filter.outputImage.extent];
UIImage *newImage = [UIImage imageWithCGImage:cgiimage scale:1.0f orientation:fromImage.imageOrientation];
CGImageRelease(cgiimage);
return newImage;
}

Related

iOS image blur effect with category

I'm trying to add a blur effect using category.
+ (UIImage *)blurImageWithImage:(UIImage*) imageName withView:(UIView*)view {
UIImage *sourceImage = imageName;
CIImage *inputImage = [CIImage imageWithCGImage:sourceImage.CGImage];
// Apply Affine-Clamp filter to stretch the image so that it does not
// look shrunken when gaussian blur is applied
CGAffineTransform transform = CGAffineTransformIdentity;
CIFilter *clampFilter = [CIFilter filterWithName:#"CIAffineClamp"];
[clampFilter setValue:inputImage forKey:#"inputImage"];
[clampFilter setValue:[NSValue valueWithBytes:&transform objCType:#encode(CGAffineTransform)] forKey:#"inputTransform"];
// Apply gaussian blur filter with radius of 30
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: #"CIGaussianBlur"];
[gaussianBlurFilter setValue:clampFilter.outputImage forKey: #"inputImage"];
[gaussianBlurFilter setValue:#10 forKey:#"inputRadius"];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgImage = [context createCGImage:gaussianBlurFilter.outputImage fromRect:[inputImage extent]];
// Set up output context.
UIGraphicsBeginImageContext(view.frame.size);
CGContextRef outputContext = UIGraphicsGetCurrentContext();
// Invert image coordinates
CGContextScaleCTM(outputContext, 1.0, -1.0);
CGContextTranslateCTM(outputContext, 0, view.frame.size.height);
// Draw base image.
CGContextDrawImage(outputContext, view.frame, cgImage);
// Apply white tint
CGContextSaveGState(outputContext);
CGContextSetFillColorWithColor(outputContext, [UIColor colorWithWhite:1 alpha:0.2].CGColor);
CGContextFillRect(outputContext, view.frame);
CGContextRestoreGState(outputContext);
// Output image is ready.
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage; }
then I call this function inside a UIView like this:
UIImage *image = [UIImage imageNamed:#"xxx"]
UIImageView *page = [[UIImageView alloc] initWithImage:[UIImage blurImageWithImage:image withView:self]];
If I add this function directly in the class, it works, but not if I do it in UIImage category.
I had face same problem earlier. But thank fully I am getting the solution.
Please follow step. Make sure your blur image function working fine.
1) In category add instance method instead of class method.
ex.
- (UIImage *)blurImageWithImage:(UIImage*) imageName withView:(UIView*)view
2) Import category in your VC
3) Use category, ex
UIImage *image = [UIImage imageNamed:#"xxx"]
UIImageView *page = [[UIImageView alloc] initWithImage:[image blurImageWithImage:image withView:self]];
Let me know this solution is working fine for you.
Turns out the problem was I forgot to add "-" when doing context translate.
So what I ended up doing is I create a class method.
Interface:
+ (UIImage *)blurImageWithImageName:(NSString*) imageName withView:(UIView*)view;
Implementation :
+ (UIImage *)blurImageWithImageName:(NSString*) imageName withView:(UIView*)view {
UIImage *sourceImage = [UIImage imageNamed:imageName];
CIImage *inputImage = [CIImage imageWithCGImage:sourceImage.CGImage];
// Apply Affine-Clamp filter to stretch the image so that it does not
// look shrunken when gaussian blur is applied
CGAffineTransform transform = CGAffineTransformIdentity;
CIFilter *clampFilter = [CIFilter filterWithName:#"CIAffineClamp"];
[clampFilter setValue:inputImage forKey:#"inputImage"];
[clampFilter setValue:[NSValue valueWithBytes:&transform objCType:#encode(CGAffineTransform)] forKey:#"inputTransform"];
// Apply gaussian blur filter with radius of 30
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: #"CIGaussianBlur"];
[gaussianBlurFilter setValue:clampFilter.outputImage forKey: #"inputImage"];
[gaussianBlurFilter setValue:#10 forKey:#"inputRadius"];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgImage = [context createCGImage:gaussianBlurFilter.outputImage fromRect:[inputImage extent]];
// Set up output context.
UIGraphicsBeginImageContext(view.frame.size);
CGContextRef outputContext = UIGraphicsGetCurrentContext();
// Invert image coordinates
CGContextScaleCTM(outputContext, 1.0, -1.0);
CGContextTranslateCTM(outputContext, 0, -view.frame.size.height);
// Draw base image.
CGContextDrawImage(outputContext, view.frame, cgImage);
// Apply white tint
CGContextSaveGState(outputContext);
CGContextSetFillColorWithColor(outputContext, [UIColor colorWithWhite:1 alpha:0.2].CGColor);
CGContextFillRect(outputContext, view.frame);
CGContextRestoreGState(outputContext);
// Output image is ready.
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}

CIGaussianBlur issues

After much research I found out how to get iOS's CIGaussianBlur to semi work. I am trying to blur an UIImageView, but instead it's blurring the entire view. Here is my code:
// Get a UIImage from the UIView
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Blur the UIImage
CIImage *imageToBlur = [CIImage imageWithCGImage:viewImage.CGImage];
CIFilter *gaussianBlurFilter = [CIFilter filterWithName:#"CIGaussianBlur"];
[gaussianBlurFilter setValue:imageToBlur forKey:#"inputImage"];
[gaussianBlurFilter setValue:[NSNumber numberWithFloat:2] forKey:#"inputRadius"];
CIImage *resultImage = [gaussianBlurFilter valueForKey:#"outputImage"];
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];
// Place the UIImage in a UIImageView
_backgroundImage = [[UIImageView alloc] initWithFrame:self.view.bounds];
_backgroundImage.image = endImage;
[self.view addSubview:_backgroundImage];
(My UIImageView's name is backgroundImage)
Thanks for any help!
Are you trying to create the iOS 7 blur? If so you can use this category...
https://github.com/iGriever/TWSReleaseNotesView/tree/master/TWSReleaseNotesView
It is one that an apple employee released to make it easy to recreate the iOS 7 blur.
Just take the snap shot and then use the category to "applyLightEffects" etc...

Aligning two images when merging them with CIFilter

I'm merging two images together by using the CIFilter #"CIDarkenBlendMode". It works fine except for one thing. I want the images to be exactly aligned on top of each other regardless of the image size but I am not able to achieve this. Do I have to create my own filter?
This is what I get:
This is what I want:
My merge-code:
-(void)mergeImagesWithCIImage:(UIImage*)image
{
CIImage *topImage = [[CIImage alloc]initWithImage:image];
CIImage *scaledImage = [self scaleImageWithCIImage:topImage];
CIImage *backgroundImage = [[CIImage alloc]initWithImage:self.vImage.image];
CIFilter *darkenFilter = [CIFilter filterWithName:#"CIDarkenBlendMode" keysAndValues:kCIInputImageKey,scaledImage,
#"inputBackgroundImage",backgroundImage,nil];
CIImage *filterOutputImage = darkenFilter.outputImage;
CIContext *ctx = [CIContext contextWithOptions:nil];
CGImageRef createdImage = [ctx createCGImage:filterOutputImage fromRect:filterOutputImage.extent];
UIImage *outputImage = [UIImage imageWithCGImage:createdImage];
CGImageRelease(createdImage);
createdImage = nil;
self.vImage.image = outputImage;
}
Instead of using a CIFilter I used:
[_image drawInRect:CGRectMake(centerX,centerY,_image.size.width,_image.size.height) blendMode:kCGBlendModeDarken alpha:0.8];
and centered the images.

Changing image hue iOS

I want to change hue of an image using slider. what I did is:
float slideValue = sldHueChange.value;
beginImage= [CIImage imageWithCGImage:imgBorder.image.CGImage];
context = [CIContext contextWithOptions:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];
filter= [CIFilter filterWithName:#"CIHueAdjust"];
[filter setValue:beginImage forKey:kCIInputImageKey];
[filter setValue:[NSNumber numberWithFloat:slideValue] forKey:#"inputAngle" ];
CIImage *outputImage = [filter outputImage];
CGImageRef cgimg =[context createCGImage:outputImage fromRect:[outputImage extent]];
UIImage *newImg = [UIImage imageWithCGImage:cgimg];
[imgBorder setImage:newImg];
CGImageRelease(cgimg);
Its working. But it is not smooth. I want a to change hue of image very smoothly.
If you have idea to make a smooth hue changer please share it. I really need it. Thanks in advance.
I would suggest you to use the amazing GPUImage from Brad, it has a lot of filters, or you can try to use the GPU render for CIContext, changing the boolean to NO in the options dictionary for the CIContext creation.
Now what I'm doing is:
CGRect rect = CGRectMake(0, 0, selectedBorderForChangingHue.size.width, selectedBorderForChangingHue.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context1 = UIGraphicsGetCurrentContext();
CGContextClipToMask(context1, rect, selectedBorderForChangingHue.CGImage);
CGContextSetFillColorWithColor(context1, [[UIColor colorWithHue:sldHueChange.value/255.0f saturation:1.0f brightness:1.0f alpha:1.0f] CGColor]);
CGContextFillRect(context1, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage *flippedImage = [UIImage imageWithCGImage:img.CGImage scale:1.0 orientation: UIImageOrientationDownMirrored];
imgBorder.image = flippedImage;
and it is working fine for me. and it is very smooth.

Applying a CIFilter to a CALayer

CI Filters are now available in iOS 5, and I'm trying to apply one to a CALayer, the way you'd do it on Mac. Here's my code:
CALayer *myCircle = [CALayer layer];
myCircle.bounds = CGRectMake(0,0,30,30);
myCircle.position = CGPointMake(100,100);
myCircle.cornerRadius = 15;
myCircle.borderColor = [UIColor whiteColor].CGColor;
myCircle.borderWidth = 2;
myCircle.backgroundColor = [UIColor whiteColor].CGColor;
CIFilter *blurFilter = [CIFilter filterWithName:#"CIDiscBlur"];
[blurFilter setDefaults];
[blurFilter setValue:[NSNumber numberWithFloat:5.0f] forKey:#"inputRadius"];
[myCircle setFilters:[NSArray arrayWithObjects:blurFilter, nil]];
[self.view.layer addSublayer:myCircle];
My white circle draws fine, but the filter isn't applied.
Aside from the fact that CIDiskBlur is not available (as of iOS SDK 5.1) and that setFilters: seems to be not available either you could do the following:
Create the input CIImage from the contents of your layer:
CIImage *inputImage = [CIImage imageWithCGImage:(CGImageRef)(myCircle.contents)];`
Apply your filters and get the result in an CGImageRef:
CIFilter *filter = [CIFilter filterWith...];// A filter that is available in iOS or a custom one :)
...
CIImage *outputImage = [filter outputImage];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]];
Finally set the CGImageRef to the layer:
[myCircle setContents:(id)cgimg];
This should work :)

Resources