CodingMeSwiftly
CodingMeSwiftly

Reputation: 3261

iOS UIImage masked border

Is there a way in iOS to add a border to an image which is not a simple rectangle ?

I have successfully tinted an image using the following code:

- (UIImage *)imageWithTintColor:(UIColor *)tintColor
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, self.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, kCGBlendModeNormal);

    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextClipToMask(context, rect, self.CGImage);

    [tintColor setFill];
    CGContextFillRect(context, rect);

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return tintedImage;
}

Lets say for example i wanted to add a blue border to this image (Note: this is NOT an 'A' NSString, but an UIImage object example)

enter image description here

When i alter the code above to [color setStroke] and CGContextStrokeRect(context, rect), the image just disappears.

I've already learned from SO that this is possible using CoreImage + EdgeDetection, but isn't there a "simple" CoreGraphics - way similar to tinting an image ?

Thank you!

-- EDIT --

Please note that I want to add the border to the image itself. I don't want to create the border effect through an UIImageView !

The border should match the shape of the image before applying the border. In this case: blue outline for the outside + inside of the 'A'.

Upvotes: 2

Views: 2235

Answers (5)

Aleksander
Aleksander

Reputation: 2815

I realize this was asked 2 years ago and is probably not still relevant to you, however I'd like to submit my solution in case anyone else stumbles upon this question while looking for an answer (like I just did).

One way to generate a border around an image is by tinting the image to your border color (say black), and then overlaying a smaller copy of your image onto the middle of the tinted one.

I built my solution upon your imageWithTintColor:tintColor function as an extension to UIImage in Swift 3:

extension UIImage {

    func imageByApplyingBorder(ofSize borderSize: CGFloat, andColor borderColor: UIColor) -> UIImage {
        /* 
            Get the scale of the smaller image
            If borderSize is 10% then smaller image should be 90% of its original size
        */
        let scale: CGFloat = 1.0 - borderSize

        // Generate tinted background image of original size
        let backgroundImage = imageWithTintColor(borderColor)
        // Generate smaller image of scale
        let smallerImage = imageByResizing(by: scale)

        UIGraphicsBeginImageContext(backgroundImage.size)

        // Draw background image first, followed by smaller image in the middle
        backgroundImage.draw(at: CGPoint(x: 0, y: 0))
        smallerImage.draw(at: CGPoint(
            x: (backgroundImage.size.width - smallerImage.size.width) / 2,
            y: (backgroundImage.size.height - smallerImage.size.height) / 2
        ))

        let borderedImage = UIGraphicsGetImageFromCurrentImageContext()!

        UIGraphicsEndImageContext()

        return borderedImage
    }

    func imageWithTintColor(_ color: UIColor) -> UIImage {
        UIGraphicsBeginImageContext(size)
        let context = UIGraphicsGetCurrentContext()!

        // Turn up-side-down (later transformations turns image back)
        context.translateBy(x: 0, y: size.height)
        context.scaleBy(x: 1.0, y: -1.0)

        context.setBlendMode(.normal)

        // Mask to visible part of image (turns image right-side-up)
        context.clip(to: CGRect(x: 0, y: 0, width: size.width, height: size.height), mask: self.cgImage!)

        // Fill with input color
        color.setFill()
        context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))

        let tintedImage = UIGraphicsGetImageFromCurrentImageContext()!

        UIGraphicsEndImageContext()

        return tintedImage
    }

    func imageByResizing(by scale: CGFloat) -> UIImage {
        // Determine new width and height
        let width = scale * size.width
        let height = scale * size.height

        // Draw a scaled down image
        UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0.0)
        draw(in: CGRect(x: 0, y: 0, width: width, height: height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return newImage
    }

}

Please note that the borderSize parameter of imageByApplyingBorder:ofSize:andColor: is given as a percentage of the original image size. If your image is 100x100 px and borderSize = 0.1, then your will get an image of size 100x100 px with a 10x10 px internal border.*

Here is an example image generated using the above function on a 1000x1000px circular center clip of one of the stock iOS Simulator photos:

Example output

Any suggestions for optimizations or other approaches are welcome.

Upvotes: 2

Denis Kutlubaev
Denis Kutlubaev

Reputation: 16184

If someone looks for an outside transparent border for UIImageView or any other View, look at my solution here or here.

Upvotes: 0

Adithya
Adithya

Reputation: 4705

This is not a very satisfying method I would say, but works to some extent.

You can make use of adding shadow to the layer. For this you need to strip off the white portion in the image, leaving the character surrounded by alpha.

I used the below code.

UIImage *image = [UIImage imageNamed:@"image_name_here.png"];

CALayer *imageLayer = [CALayer layer];
imageLayer.frame = CGRectMake(0, 0, 200.0f, 200.0f);
imageLayer.contents = (id)image.CGImage;
imageLayer.position = self.view.layer.position;

imageLayer.shadowColor = [UIColor whiteColor].CGColor;
imageLayer.shadowOffset = CGSizeMake(0.0f, 0.0f);
imageLayer.shadowOpacity = 1.0f;
imageLayer.shadowRadius = 4.0f;

[self.view.layer addSublayer:imageLayer];

And the result would be something like this.

And the result would be

Upvotes: 2

Try this

 #import <QuartzCore/QuartzCore.h>


 [yourUIImageView.layer setBorderColor:[UIColor blueColor].CGColor];

 [yourUIImageView.layer setBorderWidth:6.0];

Upvotes: 0

Ashutosh
Ashutosh

Reputation: 2225

You can use below code to add a border to the UIImageView:

[self.testImage.layer setBorderColor:[UIColor blueColor].CGColor];
[self.testImage.layer setBorderWidth:5.0];

Upvotes: 0

Related Questions