I need to be able to programmatically draw on an image, and save that image for later use. Say, draw a line on specific x and y coordinates on the image, save the image, and display it onto a simple view controller. How would I go about doing this in Swift? (Preferably Swift 2, I am still in development and haven't updated my mac to Sierra)
Update: Possibly something to do with converting a UIImage to a CGLayer, drawing on it, and then converting it back to a UIImage.
我需要能够以编程的方式绘制图像,并保存该图像以供以后使用。例如,在图像上的特定x和y坐标上画一条线,保存图像,并将其显示在一个简单的视图控制器上。我该如何用Swift来做这件事呢?(最好是Swift 2,我还在开发中,还没有将mac升级到Sierra)更新:可能与将UIImage转换为CGLayer有关,在此基础上进行绘制,然后将其转换回UIImage。
5
It's simple:
很简单:
Make an image graphics context. (Before iOS 10, you would do this by calling UIGraphicsBeginImageContextWithOptions
. In iOS 10 there's another way, UIGraphicsImageRenderer, but you don't have to use it if you don't want to.)
创建一个图像图形上下文。(在ios10之前,您可以通过调用UIGraphicsBeginImageContextWithOptions来实现这一点。在ios10中有另一种方式,UIGraphicsImageRenderer,但如果你不想使用,你也不必使用它。
Draw (i.e. copy) the image into the context. (UIImage actually has draw...
methods for this very purpose.)
将图像绘制(即复制)到上下文中。(用户界面图像实际上画…方法就是为了达到这个目的。
Draw your line into the context. (There are CGContext functions for this.)
在上下文中画线。(这里有CGContext函数。)
Extract the resulting image from the context. (For example, if you used UIGraphicsBeginImageContextWithOptions
, you would use UIGraphicsGetImageFromCurrentImageContext
.) Then close the context.
从上下文中提取生成的图像。(例如,如果您使用UIGraphicsBeginImageContextWithOptions,您将使用UIGraphicsGetImageFromCurrentImageContext)。然后关闭上下文。
6
All you need to do is create and get an Image Context object and acess all its powerfull drawing methods. You can learn more about the CGContext object features here.
您所需要做的就是创建和获取一个图像上下文对象,并使用它的所有powerfull绘图方法。您可以在这里了解更多关于CGContext对象的特性。
This function draws a line and a circle on an UIImage and returns the modified image:
此函数在UIImage上绘制一条线和一个圆,并返回修改后的图像:
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
}
2
Updated Answer: Once you get the From and To coordinates, here is how to draw a line in a UIImage with those coordinates. From and To coordinates are in image pixels.
更新后的答案:一旦你得到了从和到坐标,这里是如何绘制一条线在一个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 }
2
Xcode 9.1, Swift 4
Xcode 9.1,斯威夫特4
extension 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
}
}
extension UIImageView
扩展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)
}
}
}
Parent Image:
父母的形象:
Child Image:
儿童形象:
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)
}
}
Result 1
结果1
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)
}
}
Result 2
结果2
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)
}
}
Result 3
结果3
Don't forget to add Solution code 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)
}
}
}