如何在Swift上绘制图像?

我需要能够以编程方式绘制图像,并保存该图像供以后使用。 说,在图像上的特定x和y坐标上画一条线,保存图像,并将其显示在一个简单的视图控制器上。 我将如何去在Swift做这个? (最好Swift 2,我仍在开发中,并没有更新我的Mac到Sierra)

更新:可能与将UIImage转换为CGLayer,绘制它,然后将其转换回UIImage有关。

这很简单:

  1. 制作图像graphics上下文。 (在iOS 10之前,你可以通过调用UIGraphicsBeginImageContextWithOptions来做到这一点,在iOS 10中有另一种方法,UIGraphicsImageRenderer,但是如果你不想使用的话,你不必使用它)。

  2. 将图像绘制(即复制)到上下文中。 (UIImage实际上已经draw...了这个目的的方法。)

  3. 在上下文中绘制线条。 (这里有CGContext函数。)

  4. 从上下文中提取结果图像。 (例如,如果使用了UIGraphicsBeginImageContextWithOptions ,则可以使用UIGraphicsGetImageFromCurrentImageContext 。)然后closures上下文。

更新的答案:一旦你得到的From和To的坐标,这里是如何在这些坐标UIImage中画一条线。 From和To坐标位于图像像素中。

 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 } 

所有你需要做的是创build并获得一个图像上下文对象,并获得其所有强大的绘图方法。 你可以在这里了解更多关于CGContext对象的function。

此函数在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 } 

细节

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

图像样本

父图像:

在这里输入图像说明

儿童图像:

在这里输入图像说明


用法示例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

在这里输入图像说明


用法示例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

在这里输入图像说明


用法示例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

在这里输入图像说明

完整的示例代码

不要忘记在这里添加解决scheme代码

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