web-dev-qa-db-ja.com

swiftでuiimageに色付きの境界線を追加する方法

レイヤー(borderWidth、borderColorなど)を使用して、UIImageViewにボーダーを追加するのは非常に簡単です。画像ビューではなく画像に境界線を追加する可能性はありますか?誰か知っていますか?

更新:

以下の提案に従い、extensionを使用しました。ありがとうございましたが、期待した結果が得られませんでした。これが私のコードです。なにが問題ですか?

import UIKit
    class ViewController: UIViewController {

    var imageView: UIImageView!
    var sizeW = CGFloat()
    var sizeH = CGFloat()

    override func viewDidLoad() {
        super.viewDidLoad()

        sizeW = view.frame.width
        sizeH = view.frame.height

        setImage()
    }

    func setImage(){

        //add image view
        imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: sizeW/2, height: sizeH/2))
        imageView.center = view.center
        imageView.tintColor = UIColor.orange
        imageView.contentMode = UIViewContentMode.scaleAspectFit

        let imgOriginal = UIImage(named: "Plum")!.withRenderingMode(.alwaysTemplate)
        let borderImage = imgOriginal.imageWithBorder(width: 2, color: UIColor.blue)
        imageView.image = borderImage

        view.addSubview(imageView)

    }



}


    extension UIImage {
    func imageWithBorder(width: CGFloat, color: UIColor) -> UIImage? {
        let square = CGSize(width: min(size.width, size.height) + width * 2, height: min(size.width, size.height) + width * 2)
        let imageView = UIImageView(frame: CGRect(Origin: CGPoint(x: 0, y: 0), size: square))
        imageView.contentMode = .center
        imageView.image = self
        imageView.layer.borderWidth = width
        imageView.layer.borderColor = color.cgColor
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        imageView.layer.render(in: context)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}

赤い枠が付いた2番目の画像は、多かれ少なかれ私が必要とするものです。

enter image description here

enter image description here

8
Roman

これは私がSwift 4.で書いたUIImage拡張機能です。IOSDealBreakerがこれはすべて画像処理に関するものであり、いくつかの特定のケースが発生する可能性があります。透明な背景のpng画像が必要です。オリジナルよりも大きい場合のサイズ。

  • まず、画像の色付きの「シェード」バージョンを取得します。
  • 次に、指定された原点の周りにシェードイメージを描画して再描画します(この場合は(0,0)境界線の太さの距離で)
  • ソース画像を原点に描画して、前景に表示されるようにします。
  • 境界線が元の四角形から外れる場合は、画像を拡大する必要がある場合があります。

私のメソッドは、多くのutilメソッドとクラス拡張を使用しています。以下は、別のポイントを中心にベクトル(実際にはポイント)を回転させるためのいくつかの計算です。 別のCGPointを中心に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)
    }
}

透明な背景を持つ画像に色を付けるためにカスタムCIFilterを作成しました: SwiftでUIImageに色を付ける

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
        }
    }

この時点で、これを機能させるためのすべてが揃っているはずです。

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
    }
}
5
herme5

これを実現する方法は次のとおりです。

以下にextensionをコードに追加します。

extension UIImage {
    func imageWithBorder(width: CGFloat, color: UIColor) -> UIImage? {
        let square = CGSize(width: min(size.width, size.height) + width * 2, height: min(size.width, size.height) + width * 2)
        let imageView = UIImageView(frame: CGRect(Origin: CGPoint(x: 0, y: 0), size: square))
        imageView.contentMode = .center
        imageView.image = self
        imageView.layer.borderWidth = width
        imageView.layer.borderColor = color.cgColor
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        imageView.layer.render(in: context)
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
}

そして、あなたはそれをこのように使うことができます:

let imgOriginal = UIImage.init(named: "Richie_Rich")
img.image = imgOriginal?.imageWithBorder(width: 2, color: UIColor.blue)

そして結果は:

enter image description here

ここ は角が丸い元の投稿ですが、あなたがそれを要求しなかったため、そのコードを削除しました。

3
Dharmesh Kheni

UIImageにこの単純な拡張機能を使用する

extension UIImage {

    func outline() -> UIImage? {

        UIGraphicsBeginImageContext(size)
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        self.draw(in: rect, blendMode: .normal, alpha: 1.0)
        let context = UIGraphicsGetCurrentContext()
        context?.setStrokeColor(red: 1.0, green: 0.5, blue: 1.0, alpha: 1.0)
        context?.setLineWidth(5.0)
        context?.stroke(rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage

    }

}

ボーダーがピンクのイメージになります。

0
Arun Kumar

画像の境界線はiOSの画像処理領域に属します。 UIViewの境界線としては簡単ではありませんが、かなり深いのですが、遠くまで進んでよければ、ここにライブラリと旅のヒントがあります https://github.com/BradLarson/GPUImage =

gPUImageThresholdEdgeDetectionFilterを使用してみてください

またはOpenCVを試してください https://docs.opencv.org/2.4/doc/tutorials/ios/image_manipulation/image_manipulation.html

0
ZameerMoh