Wie füge ich einem Bild in iOS Swift Text hinzu?

80

Ich habe mich umgesehen und konnte nicht herausfinden, wie man Text aufnimmt, ihn auf ein Bild legt und dann die beiden zu einem einzigen kombiniert UIImage.

Ich habe Google mit den Suchbegriffen erschöpft, die mir einfallen. Wenn also jemand eine Lösung oder zumindest einen Hinweis hat, auf den er verweisen kann, wäre er sehr dankbar.

Christopher Wade Cantley
quelle

Antworten:

184

Ok ... ich habe es herausgefunden:

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

}

Um es zu nennen, geben Sie einfach ein Bild ein:

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

Die folgenden Links haben mir dabei geholfen, das klar zu stellen:

Swift - Zeichnen von Text mit drawInRect: withAttributes:

Wie schreibe ich Text auf ein Bild in Objective-C (iOS)?

Das ursprüngliche Ziel war es, ein dynamisches Bild zu erstellen, das ich verwenden kann, um AnnotaionViewbeispielsweise einen Preis an einem bestimmten Ort auf einer Karte zu platzieren, und das hat sich hervorragend bewährt. Hoffe, das hilft jemandem, der versucht, das Gleiche zu tun.

Für 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!
 }

Für 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!
 }

Für 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!
}
Christopher Wade Cantley
quelle
1
super hilfreich! Vielen Dank für die Veröffentlichung Ihres Codes. und so gut kommentiert.
Aspen
Können diese Texte oder deren Container auf Tap-Ereignisse reagieren?
PPrasai
1
@JadeSync Wenn das Objekt, in das Sie das Bild importieren, anklickbar ist, dann ja. Es ist jedoch nicht der Text, auf den geklickt werden kann, sondern der Container, in dem die endgültigen Bilder verwendet werden und der angeklickt werden muss. Genau das habe ich mit diesem Bild gemacht, weil ich eine Möglichkeit brauchte, eine anklickbare Markierung auf einer Karte zu haben, und die Markierung musste Text in einem Bild haben. Die Markierung verfügt über einen Klickereignis-Delegaten, sodass nicht das Bild, auf das sie klicken, sondern die Markierung, die sie enthält.
Christopher Wade Cantley
2
Wenn ich den Punkt rechts unten im Bild setze und der Text zu lang ist, erstreckt er sich vom Bild weg. Irgendwelche Vorschläge, wie der Text links vom Punkt ausgerichtet werden kann, anstatt sich rechts vom Bild zu erstrecken?
Chickenparm
Ich bin auch auf dieses Problem gestoßen, und ehrlich gesagt hängt es von der Schriftart und -größe sowie von der Größe des Bildes ab, wo der Text im Bild beginnen soll, da Sie möglicherweise nicht auf einen PNG-Schatten treten möchten. Dies war ein Versuch und Irrtum, bei dem ich ein Zeichen hinzufügen, herausfinden musste, wie viele Pixel der Startpunkt verschoben werden muss, um ihn zu erhalten, und dann eine schnelle Berechnung durchführen, um den gleitenden Startpunkt basierend auf der Anzahl der Zeichen (nach oben) zu ermitteln bis zu einem Maximum basierend darauf, wie es aussieht). Ich wollte nicht zu kompliziert werden, also ging ich auf die bloße Lösung für meine Frage ein.
Christopher Wade Cantley
20

Meine einfache Lösung:

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
}
Darkngs
quelle
Dank des Codes, aber wie man die Schriftgröße anpasst, ist jede Bildgröße bei unterschiedlicher Textlänge unterschiedlich. Wie kann ich das dynamisch machen?
iPhoneDev
Ich denke, Sie sollten Autoshrink verwenden. Stellen Sie die maximale Schriftgröße für die maximale Breite des Etiketts ein und fügen Sie Folgendes hinzu: label.adjustsFontSizeToFitWidth = true & label.minimumScaleFactor = 0.5
Darkngs
Gibt es eine Möglichkeit, Beschriftungstext hinzuzufügen, der an einer der Ecken ausgerichtet ist?
Ashh
11

Sie können auch einen CATextLayer erstellen.

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

Espe
quelle
1
Ich liebe Rays Sachen. Danke für die alternative Methode!
Christopher Wade Cantley
2
Sie fügen einer Ansicht hier eine
Textebene hinzu
1
Erwähnenswert, wenn man den Text vertikal ausrichten möchte,
JKRT
5

Ich habe eine Erweiterung für die Verwendung überall erstellt:

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

}

Verwendung: Überall auf Ihrem ViewController, wo Sie die Größe und das Etikett zum Hinzufügen haben, verwenden Sie es wie folgt:

let newImageWithOverlay = UIImage.createImageWithLabelOverlay(label: labelToAdd, imageSize: size, image: editedImage)
Ankit Kumar Gupta
quelle
1
Genial! Vielen Dank für Ihren Beitrag.
Christopher Wade Cantley
Es zeigt weißen Hintergrund, auch wenn ich transparentes Bild verwendet habe
EI Captain v2.0
Was machst du, um es in eine Ansicht zu bringen oder auf den Server hochzuladen?
Ankit Kumar Gupta
Nehmen Sie einfach das Bild und zeigen Sie es in der Bildansicht. Es zeigt weißen Hintergrund
EI Captain v2.0
Ihre Bildansicht und ihre Übersicht müssen einen klaren Hintergrund haben. Wenn Sie es im PNG-Format auf dem Server veröffentlichen, wird es so sein, wie Sie es möchten. Mach das und überprüfe. Oder versuchen Sie es einmal lokal zu speichern.
Ankit Kumar Gupta
3

Für schnelle 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!
}
Yasin Aktimur
quelle
1

Ich kann in Ihrer ersten Frage nichts sehen, was darauf hindeutet, dass dies ausschließlich im Code erfolgen muss. Warum also nicht einfach ein UILabel im Interface Builder hinzufügen und Einschränkungen hinzufügen, um ihm die gleiche Länge und Breite wie Ihrem Bild zu geben, es vertikal zu zentrieren und horizontal (oder wie auch immer Sie es platzieren möchten), löschen Sie den Beschriftungstext, stellen Sie die Schriftart, Größe, Farbe usw. des Textes nach Bedarf ein (einschließlich Aktivieren von Autoshrink mit der von Ihnen benötigten Mindestgröße oder -skala) und stellen Sie sicher, dass der Hintergrund transparent ist.

Verbinden Sie es dann einfach mit einem IBOutlet und legen Sie den Text nach Bedarf im Code fest (z. B. in viewWillAppear oder mithilfe eines ViewModel-Ansatzes und Festlegen bei der Initialisierung Ihrer Ansicht / Ihres Viewcontrollers).

Gsp
quelle
0

Ich habe diese Grundkomponenten ausprobiert. Hoffe es wird funktionieren.

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
    }
Muhammad Haroon Iqbal
quelle