Search code examples
swiftxcodemacosnsimage

Is it possible to generate NSImage from string?


I've seen a couple of solutions on how to generate UIImage with string How to generate an UIImage from custom text in Swift, but replicating the same thing on macOS seems difficult since their Graphic library is different. Please I just need to convert a string to NSImage so I can use it on a mac application.


Solution

  • You just need to create a new NSImage object, lockFocus, draw the attributed string on it and unlockFocus again:

    extension NSAttributedString {
        func image(foregroundColor: NSColor? = nil, backgroundColor: NSColor? = nil) -> NSImage {
            let size = self.size()
            let image = NSImage(size: size)
            image.lockFocus()
            let mutableStr = NSMutableAttributedString(attributedString: self)
            if let foregroundColor = foregroundColor,
               let backgroundColor = backgroundColor {
                mutableStr.setAttributes([.foregroundColor: foregroundColor,
                                          .backgroundColor: backgroundColor],
                                         range: .init(location: 0, length: length))
            }
            else
            if let foregroundColor = foregroundColor {
                mutableStr.setAttributes([.foregroundColor: foregroundColor],
                                         range: .init(location: 0, length: length))
            }
            else
            if let backgroundColor = backgroundColor {
                mutableStr.setAttributes([.backgroundColor: backgroundColor],
                                         range: .init(location: 0, length: length))
            }
            mutableStr.draw(in: .init(origin: .zero, size: size))
            image.unlockFocus()
            return image
        }
    }
    

    let stackOverflow = NSAttributedString(string: "StackOverflow")
    stackOverflow.image()
    stackOverflow.image(foregroundColor: .red)
    stackOverflow.image(backgroundColor: .white)
    stackOverflow.image(foregroundColor: .red, backgroundColor: .green)
    

    extension StringProtocol {
        func image(foregroundColor: NSColor? = nil, backgroundColor: NSColor? = nil) -> NSImage {
            NSAttributedString(string: .init(self)).image(foregroundColor: foregroundColor, backgroundColor: backgroundColor)
        }
    }
    

    "StackOverflow".image()
    

    edit/update:

    If you would like to create an image from a label (NSTextField)

    extension NSView {
        var image: NSImage? {
            guard let bitmapImageRep = bitmapImageRepForCachingDisplay(in: bounds) else { return nil }
            cacheDisplay(in: bounds, to: bitmapImageRep)
            guard let cgImage = bitmapImageRep.cgImage else { return nil }
            return NSImage(cgImage: cgImage, size: bounds.size)
        }
    }
    

    let label = NSTextField(labelWithString: "StackOverflow")
    label.textColor = .blue
    label.backgroundColor = .clear
    label.sizeToFit()
    label.image