0

I want to create a radial gradient mask to create a hole in the picture, so that you can see through the picture. I created an overlaying image with a hole and the image beneath is visible, like below:

enter image description here

I am able to create this image using CGImageMaskCreate() successfully. But due to the unusual behaviour of CGImageMaskCreate() in iOS 10.0, I am looking for another solutions.

One such solution is to create image mask using the UIView's maskView property. I am able to write the code for creating the above mentioned image effect using maskView. But its not giving the correct results.

I am not very good with Core Graphics, maybe that's why I am not able to figure out where I am going wrong. My code is:

CGRect rect = CGRectMake(0.0, 0.0, self.view.bounds.size.width, self.view.bounds.size.height);
CGSize size = self.view.bounds.size;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat radius = 160.0;
CGPoint center = CGPointMake(150.0, 150.0);
CGFloat components[] = {1.0,1.0,1.0,1.0,   1.0,1.0,1.0,1.0,    1.0,1.0,1.0,1.0,     1.0,1.0,1.0,1.0,    1.0,1.0,1.0,0.5,    1.0,1.0,1.0,0.0};
CGFloat locations[] = {0.0, 0.1, 0.2, 0.8, 0.9, 1.0};

//creating bitmap context
CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, size.width*4, colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
//creating gradient
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 6);
CGContextDrawRadialGradient(context, gradient, center, 0.1, center, radius, 0);
//get the gradient image
CGImageRef imageHole = CGBitmapContextCreateImage(context);
UIImage *img = [UIImage imageWithCGImage:imageHole];
CGGradientRelease(gradient);

//creating mask view whose alpha channels will be used for masking
UIImageView *maskImgView = [[UIImageView alloc] initWithFrame:CGRectMake(50.0, 50.0, 100.0, 100.0)];
[maskImgView setImage:img];

//This is the view on which I want to perform masking
UIImageView *mainView = [[UIImageView alloc] initWithFrame:self.view.bounds];
[mainView setImage:[UIImage imageNamed:@"insta-logo.png"]];
mainView.maskView = maskImgView;
[self.view addSubview:mainView];

This the result I am getting:

enter image description here

The image used is entirely filled with red color. I want the resulting image to be transparent in the gradient region so that you can through it and I want the rest of the area to be red preserving the opacity of the rest of image, like the very first picture I posted.

I want to create this effect using maskView property, because of the unusual behaviour of CAShapeLayer and CGImageMaskCreate() encountered in iOS 10 and later.

Any suggestions will be very helpful. Thank you.

Serg
  • 2,346
  • 3
  • 29
  • 38
maven25
  • 231
  • 2
  • 12
  • "the unusual behaviour of CAShapeLayer and CGImageMaskCreate() encountered in iOS 10 and later" What exactly are you referring to? – matt Feb 02 '17 at 21:13
  • Using CGImageMaskCreate() creates the mask properly but the final masked image is almost transparent. For my application, this problem occurs only in iPhone 7 and above. I suppose thats because of some issue with iOS 10. – maven25 Feb 03 '17 at 03:18
  • By the way, I got some help from this thread https://forums.developer.apple.com/thread/50854 – maven25 Feb 03 '17 at 03:19
  • No, I really don't see the relevance of that; it's about some dumb stuff people have been trying to with UIVisualEffectView, which has nothing to do with your question. As for CGImageMaskCreate(), I think I can pretty much guarantee that it hasn't changed its behavior since iOS 3; Apple wouldn't mess with something at such a deep level so basic to the drawing system. Nor do I believe that hardware would make a difference. Apologies for the skepticism, but there it is. However, I never use CGImageMaskCreate() so I can't pretend to real knowledge. – matt Feb 03 '17 at 03:30
  • The information which I got from this thread is to use maskView property. I really couldn't figure out why the same piece of code working fine on iPhone 6 is giving this problem. Just now one of friend told that its working fine on iPhone 6 running iOS 10. So now I just don't have any clue why its not working on only iPhone 7. Initially I thought maybe it could be because of the wide color gamut introduced in iPhone 7. – maven25 Feb 03 '17 at 03:37
  • I am having this exact same issue http://stackoverflow.com/questions/41151557/xcode-8-coregraphics-issue-with-iphone-7-running-ios-10 – maven25 Feb 03 '17 at 03:37
  • I always use either CALayer `mask` or UIView `mask` (as I did in my answer below) so, as I said, I don't really know about CGImageMaskCreate. Your guess about wide color is devilishly clever. You're certainly punching radial holes in my skepticism. – matt Feb 03 '17 at 03:40
  • Well that's a wild guess since the problem is occurring in a specific device and not in a specific OS. – maven25 Feb 03 '17 at 03:52
  • In iOS 10, the way to cope with wide color is to use the new UIGraphicsImageRenderer class, with a UIGraphicsImageRendererFormat whose `prefersExtendedRange` is appropriately set, to get your image format. Perhaps you need to steer clear of `CGBitmapContextCreate`, which has not been updated for this purpose. – matt Feb 04 '17 at 03:44

1 Answers1

0

I think what you're describing is something like this:

enter image description here

As you can see, I've punched a radial-gradient hole in an image view, allowing the yellow background to show through.

How was that done? It's a CIFilter ("CIRadialGradient") with clear and black color values, used as the mask of the image view.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • The problem with _your_ code is that you have no clear center in your gradient; instead of fading from a clear center to a black outside, you fade from a black center to a clear outside. In effect, your color array `components` is backwards — that's all. Fix that, and your code will work fine. Mine is the way I would probably do it, but your way provides more precise control, so go right ahead and do it your way. – matt Feb 02 '17 at 21:32