Làm cách nào để thêm văn bản vào hình ảnh trong iOS Swift?


81

Tôi đã xem xét xung quanh và đã không thành công trong việc tìm ra cách lấy văn bản, phủ nó lên một hình ảnh và sau đó kết hợp cả hai thành một UIImage.

Tôi đã cạn kiệt Google khi sử dụng các cụm từ tìm kiếm mà tôi có thể nghĩ ra nên nếu bất kỳ ai có giải pháp hoặc ít nhất là một gợi ý mà họ có thể chỉ ra sẽ được đánh giá rất cao.

Câu trả lời:


185

Ok ... tôi đã tìm ra:

func textToImage(drawText: NSString, inImage: UIImage, atPoint: CGPoint) -> UIImage{

    // Setup the font specific variables
    var textColor = UIColor.whiteColor()
    var textFont = UIFont(name: "Helvetica Bold", size: 12)!

    // Setup the image context using the passed image
    let scale = UIScreen.mainScreen().scale
    UIGraphicsBeginImageContextWithOptions(inImage.size, false, scale)

    // Setup the font attributes that will be later used to dictate how the text should be drawn
    let textFontAttributes = [
        NSFontAttributeName: textFont,
        NSForegroundColorAttributeName: textColor,
    ]

    // Put the image into a rectangle as large as the original image
    inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))

    // Create a point within the space that is as bit as the image
    var rect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)

    // Draw the text into an image
    drawText.drawInRect(rect, withAttributes: textFontAttributes)

    // Create a new image out of the images we have created
    var newImage = UIGraphicsGetImageFromCurrentImageContext()

    // End the context now that we have the image we need
    UIGraphicsEndImageContext()

    //Pass the image back up to the caller
    return newImage

}

Để gọi nó, bạn chỉ cần chuyển vào một hình ảnh:

textToImage("000", inImage: UIImage(named:"thisImage.png")!, atPoint: CGPointMake(20, 20))

Các liên kết sau đây đã giúp tôi hiểu rõ điều này:

Swift - Vẽ văn bản với drawInRect: withAttributes:

Làm thế nào để viết văn bản trên hình ảnh trong Objective-C (iOS)?

Mục tiêu ban đầu là tạo ra một hình ảnh động mà tôi có thể sử dụng AnnotaionViewchẳng hạn như đặt giá tại một vị trí nhất định trên bản đồ và điều này rất hiệu quả đối với nó. Hy vọng điều này sẽ giúp ai đó đang cố gắng làm điều tương tự.

Đối với Swift 3:

 func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
    let textColor = UIColor.white
    let textFont = UIFont(name: "Helvetica Bold", size: 12)!

    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

    let textFontAttributes = [
        NSFontAttributeName: textFont,
        NSForegroundColorAttributeName: textColor,
        ] as [String : Any]
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))

    let rect = CGRect(origin: point, size: image.size)
    text.draw(in: rect, withAttributes: textFontAttributes)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
 }

Đối với Swift 4:

 func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
    let textColor = UIColor.white
    let textFont = UIFont(name: "Helvetica Bold", size: 12)!

    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

    let textFontAttributes = [
        NSAttributedStringKey.font: textFont,
        NSAttributedStringKey.foregroundColor: textColor,
        ] as [NSAttributedStringKey : Any]
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))

    let rect = CGRect(origin: point, size: image.size)
    text.draw(in: rect, withAttributes: textFontAttributes)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
 }

Đối với Swift 5:

func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
    let textColor = UIColor.white
    let textFont = UIFont(name: "Helvetica Bold", size: 12)!

    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

    let textFontAttributes = [
        NSAttributedString.Key.font: textFont,
        NSAttributedString.Key.foregroundColor: textColor,
        ] as [NSAttributedString.Key : Any]
    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))

    let rect = CGRect(origin: point, size: image.size)
    text.draw(in: rect, withAttributes: textFontAttributes)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}

1
tuyệt vời! cảm ơn vì đã đăng mã của bạn. và rất tốt nhận xét.
Aspen

những văn bản đó hoặc vùng chứa của chúng có thể phản hồi lại các sự kiện nhấn không?
PPrasai

1
@JadeSync nếu đối tượng bạn đang nhập hình ảnh vào có thể nhấp được, thì có. Nhưng nó không phải là văn bản có thể nhấp được, nó là nơi chứa những hình ảnh cuối cùng được sử dụng trong đó cần có thể nhấp được. Trên thực tế, đó là những gì tôi đã làm với hình ảnh này vì tôi cần một cách để có một điểm đánh dấu có thể nhấp trên bản đồ và điểm đánh dấu cần có văn bản trong hình ảnh. Điểm đánh dấu có đại biểu sự kiện nhấp chuột nên nó không phải là hình ảnh mà họ đang nhấp vào mà là điểm đánh dấu chứa nó.
Christopher Wade Cantley

2
Nếu tôi đặt điểm ở dưới cùng bên phải của hình ảnh và văn bản quá dài, nó sẽ kéo dài ra khỏi hình ảnh. Bất kỳ đề xuất nào về cách để văn bản được căn chỉnh ở bên trái của điểm thay vì kéo dài hình ảnh sang bên phải?
chickenparm

Tôi cũng gặp phải vấn đề đó và thành thật mà nói, nó phụ thuộc vào loại phông chữ và kích thước cũng như kích thước của hình ảnh, nơi bạn muốn văn bản bắt đầu trong hình ảnh vì bạn có thể không muốn dẫm lên bóng PNG. Đây là một thử nghiệm - & - lỗi yêu cầu tôi thêm một ký tự, tìm ra bao nhiêu pixel để di chuyển điểm bắt đầu để đưa nó vào, sau đó thực hiện một phép tính nhanh để tìm ra điểm bắt đầu trượt dựa trên số ký tự (lên tối đa dựa trên giao diện của nó). Tôi không muốn trở nên quá phức tạp, vì vậy tôi đã đưa ra giải pháp đơn giản cho câu hỏi của mình.
Christopher Wade Cantley

20

Giải pháp đơn giản của tôi:

func generateImageWithText(text: String) -> UIImage? {
    let image = UIImage(named: "imageWithoutText")!

    let imageView = UIImageView(image: image)
    imageView.backgroundColor = UIColor.clear
    imageView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

    let label = UILabel(frame: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
    label.backgroundColor = UIColor.clear
    label.textAlignment = .center
    label.textColor = UIColor.white
    label.text = text

    UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0)
    imageView.layer.render(in: UIGraphicsGetCurrentContext()!)
    label.layer.render(in: UIGraphicsGetCurrentContext()!)
    let imageWithText = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return imageWithText
}

Thaks for code nhưng cách chỉnh cỡ chữ, mỗi kích thước ảnh khác nhau với độ dài chữ khác nhau. Làm thế nào tôi có thể làm cho điều này năng động.
iPhoneDev

Tôi nghĩ bạn nên sử dụng Autoshrink. Đặt kích thước phông chữ tối đa cho chiều rộng tối đa của nhãn và thêm: label.adjustsFontSizeToFitWidth = true & label.minimumScaleFactor = 0,5
Darkngs

có cách nào để thêm văn bản nhãn được căn chỉnh vào bất kỳ góc nào không?
Ashh

11

Bạn cũng có thể thực hiện một CATextLayer.

    // 1
let textLayer = CATextLayer()
textLayer.frame = someView.bounds

// 2
let string = String(
  repeating: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce auctor arcu quis velit congue dictum. ", 
  count: 20
)

textLayer.string = string

// 3
let fontName: CFStringRef = "Noteworthy-Light"
textLayer.font = CTFontCreateWithName(fontName, fontSize, nil)

// 4
textLayer.foregroundColor = UIColor.darkGray.cgColor
textLayer.isWrapped = true
textLayer.alignmentMode = kCAAlignmentLeft
textLayer.contentsScale = UIScreen.main.scale
someView.layer.addSublayer(textLayer)

https://www.raywenderlich.com/402-calayer-tutorial-for-ios-getting-started


1
Yêu những thứ của Ray. Cảm ơn vì phương pháp thay thế!
Christopher Wade Cantley

2
Việc bạn thêm một lớp văn bản vào một chế độ xem ở đây, không phải vào một hình ảnh
brainray 22/09/15

1
Đáng nói nếu ai đó đang tìm cách căn chỉnh theo chiều dọc văn bản, hãy xem stackoverflow.com/questions/4765461/…
JKRT

5

Tôi đã tạo một tiện ích mở rộng để sử dụng nó ở mọi nơi:

import Foundation
import UIKit
extension UIImage {

    class func createImageWithLabelOverlay(label: UILabel,imageSize: CGSize, image: UIImage) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(CGSize(width: imageSize.width, height: imageSize.height), false, 2.0)
        let currentView = UIView.init(frame: CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height))
        let currentImage = UIImageView.init(image: image)
        currentImage.frame = CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
        currentView.addSubview(currentImage)
        currentView.addSubview(label)
        currentView.layer.render(in: UIGraphicsGetCurrentContext()!)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }

}

Cách sử dụng: Bất kỳ nơi nào trên ViewController của bạn nơi bạn có kích thước và nhãn để thêm, hãy sử dụng nó như sau:

let newImageWithOverlay = UIImage.createImageWithLabelOverlay(label: labelToAdd, imageSize: size, image: editedImage)

1
Tuyệt vời! Cảm ơn vì đã đóng góp điều này.
Christopher Wade Cantley

Nó hiển thị nền trắng ngay cả khi tôi sử dụng hình ảnh trong suốt
EI Captain v2.0

Bạn đang làm gì khi đưa nó lên chế độ xem hoặc tải lên máy chủ?
Ankit Kumar Gupta

Chỉ cần lấy hình ảnh và hiển thị nó trong chế độ xem hình ảnh. Nó cho thấy nền trắng
EI Captain v2.0

Chế độ xem hình ảnh của bạn và chế độ xem siêu ảnh của nó phải có nền rõ ràng. Nếu bạn đăng nó lên máy chủ ở định dạng png thì nó sẽ như bạn muốn. Làm điều đó và kiểm tra. Hoặc thử lưu nó cục bộ một lần.
Ankit Kumar Gupta

3

Đối với nhanh 4:

func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {


    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(image.size, false, scale)

    image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))

    let rect = CGRect(origin: point, size: image.size)

    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.alignment = .center



    let attrs = [NSAttributedStringKey.font: UIFont(name: "Helvetica Bold", size: 12)!,NSAttributedStringKey.foregroundColor : UIColor.white , NSAttributedStringKey.paragraphStyle: paragraphStyle]


    text.draw(with: rect, options: .usesLineFragmentOrigin, attributes: attrs, context: nil)



    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage!
}

1

Tôi không thể thấy bất kỳ điều gì trong câu hỏi ban đầu của bạn gợi ý rằng điều này phải được thực hiện độc quyền trong mã - vậy tại sao không chỉ cần thêm Nhãn UIL trong trình tạo giao diện và thêm các ràng buộc để cung cấp cho nó cùng chiều dài và chiều rộng với hình ảnh của bạn, căn giữa theo chiều dọc theo chiều ngang (hoặc tuy nhiên bạn cần đặt nó), xóa văn bản nhãn, đặt phông chữ, kích thước, màu sắc văn bản, v.v. nếu cần (bao gồm đánh dấu chọn Autoshrink với bất kỳ kích thước hoặc tỷ lệ tối thiểu nào bạn cần) và đảm bảo nền của nó trong suốt.

Sau đó, chỉ cần kết nối nó với IBOutlet và đặt văn bản trong mã khi cần (ví dụ: trong viewWillAppear hoặc bằng cách sử dụng phương pháp ViewModel và đặt nó khi khởi chạy chế độ xem / viewcontroller của bạn).


0

Tôi đã thử các thành phần cơ bản này. Hy vọng nó sẽ hoạt động.

func imageWithText(image : UIImage, text : String) -> UIImage {

        let outerView = UIView(frame: CGRect(x: 0, y: 0, width: image.size.width / 2, height: image.size.height / 2))
        let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: outerView.frame.width, height: outerView.frame.height))
        imgView.image = image
        outerView.addSubview(imgView)

        let lbl = UILabel(frame: CGRect(x: 5, y: 5, width: outerView.frame.width, height: 200))
        lbl.font = UIFont(name: "HelveticaNeue-Bold", size: 70)
        lbl.text = text
        lbl.textAlignment = .left
        lbl.textColor = UIColor.blue

        outerView.addSubview(lbl)

        let renderer = UIGraphicsImageRenderer(size: outerView.bounds.size)
        let convertedImage = renderer.image { ctx in
            outerView.drawHierarchy(in: outerView.bounds, afterScreenUpdates: true)

        }
        return convertedImage
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.