how to add colored border to uiimage in swift

后端 未结 5 1644
礼貌的吻别
礼貌的吻别 2020-12-31 15:59

It is pretty easy to add border to UIImageView, using layers (borderWidth, borderColor etc.). Is there any possibility to add border to image, not to image view? Does somebo

5条回答
  •  不思量自难忘°
    2020-12-31 16:34

    Here is a UIImage extension I wrote in Swift 4. As IOSDealBreaker said this is all about image processing, and some particular cases may occur. You should have a png image with a transparent background, and manage the size if larger than the original.

    • First get a colorised "shade" version of your image.
    • Then draw and redraw the shade image all around a given origin point (In our case around (0,0) at a distance that is the border thickness)
    • Draw your source image at the origin point so that it appears on the foreground.
    • You may have to enlarge your image if the borders go out of the original rect.

    My method uses a lot of util methods and class extensions. Here is some maths to rotate a vector (which is actually a point) around another point: Rotating a CGPoint around another CGPoint

    extension CGPoint {
        func rotated(around origin: CGPoint, byDegrees: CGFloat) -> CGPoint {
            let dx = self.x - origin.x
            let dy = self.y - origin.y
            let radius = sqrt(dx * dx + dy * dy)
            let azimuth = atan2(dy, dx) // in radians
            let newAzimuth = azimuth + (byDegrees * CGFloat.pi / 180.0) // convert it to radians
            let x = origin.x + radius * cos(newAzimuth)
            let y = origin.y + radius * sin(newAzimuth)
            return CGPoint(x: x, y: y)
        }
    }
    

    I wrote my custom CIFilter to colorise an image which have a transparent background: Colorize a UIImage in Swift

    class ColorFilter: CIFilter {
        var inputImage: CIImage?
        var inputColor: CIColor?
        private let kernel: CIColorKernel = {
            let kernelString =
            """
            kernel vec4 colorize(__sample pixel, vec4 color) {
                pixel.rgb = pixel.a * color.rgb;
                pixel.a *= color.a;
                return pixel;
            }
            """
            return CIColorKernel(source: kernelString)!
        }()
    
        override var outputImage: CIImage? {
            guard let inputImage = inputImage, let inputColor = inputColor else { return nil }
            let inputs = [inputImage, inputColor] as [Any]
            return kernel.apply(extent: inputImage.extent, arguments: inputs)
        }
    }
    
    extension UIImage {
        func colorized(with color: UIColor) -> UIImage {
            guard let cgInput = self.cgImage else {
                return self
            }
            let colorFilter = ColorFilter()
            colorFilter.inputImage = CIImage(cgImage: cgInput)
            colorFilter.inputColor = CIColor(color: color)
    
            if let ciOutputImage = colorFilter.outputImage {
                let context = CIContext(options: nil)
                let cgImg = context.createCGImage(ciOutputImage, from: ciOutputImage.extent)
                return UIImage(cgImage: cgImg!, scale: self.scale, orientation: self.imageOrientation).alpha(color.rgba.alpha).withRenderingMode(self.renderingMode)
            } else {
                return self
            }
        }
    

    At this point you should have everything to make this work:

    extension UIImage {
        func stroked(with color: UIColor, size: CGFloat) -> UIImage {
            let strokeImage = self.colorized(with: color)
            let oldRect = CGRect(x: size, y: size, width: self.size.width, height: self.size.height).integral
            let newSize = CGSize(width: self.size.width + (2*size), height: self.size.height + (2*size))
            let translationVector = CGPoint(x: size, y: 0)
    
            UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
            if let context = UIGraphicsGetCurrentContext() {
                context.interpolationQuality = .high
    
                let step = 10 // reduce the step to increase quality
                for angle in stride(from: 0, to: 360, by: step) {
                    let vector = translationVector.rotated(around: .zero, byDegrees: CGFloat(angle))
                    let transform = CGAffineTransform(translationX: vector.x, y: vector.y)
                    context.concatenate(transform)
                    context.draw(strokeImage.cgImage!, in: oldRect)
                    let resetTransform = CGAffineTransform(translationX: -vector.x, y: -vector.y)
                    context.concatenate(resetTransform)
                }
                context.draw(self.cgImage!, in: oldRect)
    
                let newImage = UIImage(cgImage: context.makeImage()!, scale: self.scale, orientation: self.imageOrientation)
                UIGraphicsEndImageContext()
    
                return newImage.withRenderingMode(self.renderingMode)
            }
            UIGraphicsEndImageContext()
            return self
        }
    }
    

提交回复
热议问题