web-dev-qa-db-ja.com

Swiftで画像を描画するにはどうすればよいですか?

プログラムで画像を描画し、後で使用するためにその画像を保存できる必要があります。たとえば、画像上の特定のx座標とy座標に線を引き、画像を保存して、単純なView Controllerに表示します。これをSwiftでどのように行うのですか? (できればSwift 2、私はまだ開発中であり、MacをSierraにアップデートしていない)

更新:おそらくUIImageをCGLayerに変換し、その上に描画してから、それをUIImageに戻すことに関連する可能性があります。

17
caleb

簡単だ:

  1. 画像グラフィックスコンテキストを作成します。 (iOS 10より前は、UIGraphicsBeginImageContextWithOptionsを呼び出してこれを行います。iOS10には、UIGraphicsImageRendererという別の方法がありますが、必要ない場合は使用する必要はありません。)

  2. コンテキストに画像を描画(コピー)します。 (UIImageには実際にdraw...この目的のためのメソッド。)

  3. コンテキストに線を引きます。 (これにはCGContext関数があります。)

  4. コンテキストから結果の画像を抽出します。 (たとえば、UIGraphicsBeginImageContextWithOptionsを使用した場合、UIGraphicsGetImageFromCurrentImageContextを使用します。)その後、コンテキストを閉じます。

10
matt

必要なのは、Image Contextオブジェクトを作成して取得し、その強力な描画メソッドすべてにアクセスすることだけです。 CGContextオブジェクトの機能の詳細については、こちらをご覧ください こちら

この関数は、UIImageに線と円を描画し、変更された画像を返します。

スイフト4

func DrawOnImage(startingImage: UIImage) -> UIImage {

     // Create a context of the starting image size and set it as the current one
     UIGraphicsBeginImageContext(startingImage.size)

     // Draw the starting image in the current context as background       
     startingImage.draw(at: CGPoint.zero)

     // Get the current context
     let context = UIGraphicsGetCurrentContext()!

     // Draw a red line
     context.setLineWidth(2.0)
     context.setStrokeColor(UIColor.red.cgColor)
     context.move(to: CGPoint(x: 100, y: 100))
     context.addLine(to: CGPoint(x: 200, y: 200))
     context.strokePath()

     // Draw a transparent green Circle
     context.setStrokeColor(UIColor.green.cgColor)
     context.setAlpha(0.5)
     context.setLineWidth(10.0)
     context.addEllipse(in: CGRect(x: 100, y: 100, width: 100, height: 100))
     context.drawPath(using: .stroke) // or .fillStroke if need filling

     // Save the context as a new UIImage
     let myImage = UIGraphicsGetImageFromCurrentImageContext()
     UIGraphicsEndImageContext()

     // Return modified image
     return myImage
}
19
Jorge Ramírez

詳細

Xcode 9.1、Swift 4

溶液

拡張UIImage

extension UIImage {

    typealias RectCalculationClosure = (_ parentSize: CGSize, _ newImageSize: CGSize)->(CGRect)

    func with(image named: String, rectCalculation: RectCalculationClosure) -> UIImage {
        return with(image: UIImage(named: named), rectCalculation: rectCalculation)
    }

    func with(image: UIImage?, rectCalculation: RectCalculationClosure) -> UIImage {

        if let image = image {
            UIGraphicsBeginImageContext(size)

            draw(in: CGRect(Origin: .zero, size: size))
            image.draw(in: rectCalculation(size, image.size))

            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return newImage!
        }
        return self
    }
}

拡張UIImageView

    extension UIImageView {

    enum ImageAddingMode {
        case changeOriginalImage
        case addSubview
    }

    func drawOnCurrentImage(anotherImage: UIImage?, mode: ImageAddingMode, rectCalculation: UIImage.RectCalculationClosure) {

        guard let image = image else {
            return
        }

        switch mode {
        case .changeOriginalImage:
            self.image = image.with(image: anotherImage, rectCalculation: rectCalculation)

        case .addSubview:
            let newImageView = UIImageView(frame: rectCalculation(frame.size, image.size))
            newImageView.image = anotherImage
            addSubview(newImageView)
        }
    }
}

画像サンプル

親画像:

enter image description here

子画像:

enter image description here


使用例1

func sample1(imageView: UIImageView) {
    imageView.contentMode = .scaleAspectFit
    imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in
        print("parentSize = \(parentSize)")
        print("newImageSize = \(newImageSize)")
        return CGRect(x: 50, y: 50, width: 90, height: 90)
    }
}

結果1

enter image description here


使用例2

func sample2(imageView: UIImageView) {
    imageView.contentMode = .scaleAspectFit
    imageView.image = UIImage(named: "parent")
    imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in
        print("parentSize = \(parentSize)")
        print("newImageSize = \(newImageSize)")
        let sideLength:CGFloat = 90
        let indent:CGFloat = 50
        return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)
    }
}

結果2

enter image description here


使用例3

func sample3(imageView: UIImageView) {
    imageView.contentMode = .scaleAspectFill
    imageView.clipsToBounds = true
    imageView.image = UIImage(named: "parent")
    imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in
        print("parentSize = \(parentSize)")
        print("newImageSize = \(newImageSize)")
        let sideLength:CGFloat = 90
        let indent:CGFloat = 15
        return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)
    }
}

結果3

enter image description here

完全なサンプルコード

忘れずにソリューションコードを追加してください

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let imageView = UIImageView(frame: UIScreen.main.bounds)
        view.addSubview(imageView)
        sample1(imageView: imageView)
       // sample2(imageView: imageView)
       // sample3(imageView: imageView)
    }

    func sample1(imageView: UIImageView) {
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in
            print("parentSize = \(parentSize)")
            print("newImageSize = \(newImageSize)")
            return CGRect(x: 50, y: 50, width: 90, height: 90)
        }
    }

    func sample2(imageView: UIImageView) {
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "parent")
        imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in
            print("parentSize = \(parentSize)")
            print("newImageSize = \(newImageSize)")
            let sideLength:CGFloat = 90
            let indent:CGFloat = 50
            return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)
        }
    }

    func sample3(imageView: UIImageView) {
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
        imageView.image = UIImage(named: "parent")
        imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in
            print("parentSize = \(parentSize)")
            print("newImageSize = \(newImageSize)")
            let sideLength:CGFloat = 90
            let indent:CGFloat = 15
            return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)
        }
    }
}
8

IOS 10以降では、 IGraphicImageRenderer を使用できます。これは、より優れた構文といくつかの優れた機能を備えています。

Swift 4

let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { context in
    // draw your image into your view
    context.cgContext.draw(UIImage(named: "myImage")!.cgImage!, in: view.frame)
    // draw even more...
    context.cgContext.setFillColor(UIColor.red.cgColor)
    context.cgContext.setStrokeColor(UIColor.black.cgColor)
    context.cgContext.setLineWidth(10)
    context.cgContext.addRect(view.frame)
    context.cgContext.drawPath(using: .fillStroke)
}
5
appsunited

更新された回答:FromおよびTo座標を取得したら、これらの座標を使用してUIImageに線を描画する方法を次に示します。開始座標と終了座標は画像のピクセル単位です。

func drawLineOnImage(size: CGSize, image: UIImage, from: CGPoint, to: CGPoint) -> UIImage {

// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(size)

// draw original image into the context
image.drawAtPoint(CGPointZero)

// get the context for CoreGraphics
let context = UIGraphicsGetCurrentContext()

// set stroking width and color of the context
CGContextSetLineWidth(context, 1.0)
CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)

// set stroking from & to coordinates of the context
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)

// apply the stroke to the context
CGContextStrokePath(context)

// get the image from the graphics context 
let resultImage = UIGraphicsGetImageFromCurrentImageContext()

// end the graphics context 
UIGraphicsEndImageContext()

return resultImage }
5
Nadeesha Lakmal