0

I'm trying to generate an NSImage from a ttf font using Swift in Cocoa (not UIKit) and I'm struggling with the context creation at the moment.

My base code came from this project: https://github.com/reeonce/Ionicons.swift but it's designed for UIKit, so I tried translating it for Cocoa.

Here's the original code:

extension UIImage {
    public class func imageWithIonIcon(icon: Ionicons, height: CGFloat, color: UIColor) -> UIImage {
        let font = UIFont(name: "ionicons", size: height)!
        let iconSize = (icon.rawValue as NSString).sizeWithAttributes([NSFontAttributeName: font])
        UIGraphicsBeginImageContextWithOptions(iconSize, false, 0.0)
        (icon.rawValue as NSString).drawAtPoint(CGPointZero, withAttributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return image
    }
}

and here is what I have at the moment:

extension NSImage {
    public class func imageWithIonIcon(icon: Ionicons, height: CGFloat, color: NSColor) -> NSImage? {
        if let font = NSFont(name: "Ionicons", size: height) {
            let iconSize = (icon.rawValue as NSString).sizeWithAttributes([NSFontAttributeName: font])
            let context = CGBitmapContextCreate(nil, Int(iconSize.width), Int(iconSize.height), 8, Int(iconSize.width)*8, CGColorSpaceCreateDeviceRGB(), nil)
            (icon.rawValue as NSString).drawAtPoint(CGPointZero, withAttributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
            let image = NSImage(CGImage: CGBitmapContextCreateImage(context), size: iconSize)
            return image
        }
        return nil
    }
}

This gives me a runtime error because I have no idea how to initialize the context:

<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 24 bits/pixel; 3-component color space; kCGImageAlphaNone; 168 bytes/row.

Any hint for a beginner? Thanks

beeb
  • 1,187
  • 11
  • 32

1 Answers1

0

Here's an example of drawing some text in a specified Rect

    let context = NSGraphicsContext.currentContext()!.CGContext

    //// Text Drawing
    let textRect = NSMakeRect(55, 33, 88, 56)
    let textTextContent = NSString(string: "Hello, World!")
    let textStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
    textStyle.alignment = NSTextAlignment.LeftTextAlignment

    let textFontAttributes = [NSFontAttributeName: NSFont(name: "HelveticaNeue-Bold", size: 17)!, NSForegroundColorAttributeName: NSColor.blackColor(), NSParagraphStyleAttributeName: textStyle]

    let textTextHeight: CGFloat = textTextContent.boundingRectWithSize(NSMakeSize(textRect.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: textFontAttributes).size.height
    let textTextRect: NSRect = NSMakeRect(textRect.minX, textRect.minY + (textRect.height - textTextHeight) / 2, textRect.width, textTextHeight)
    NSGraphicsContext.saveGraphicsState()
    NSRectClip(textRect)
    textTextContent.drawInRect(NSOffsetRect(textTextRect, 0, 5), withAttributes: textFontAttributes)
    NSGraphicsContext.restoreGraphicsState()

Check out the docs on NSGraphicsContext for more on that https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSGraphicsContext_Class/

Will
  • 2,604
  • 2
  • 18
  • 14
  • Thanks for your reply. Unfortunately, I'm getting a `fatal error: unexpectedly found nil while unwrapping an Optional value` on the first line (setting the context constant). Am I missing something? – beeb Jul 02 '15 at 08:41
  • Oops. In 10.10, `graphicsPort` was depreciated. Try changing that first line to `let context = NSGraphicsContext.currentContext()!.CGContext` I'll modify my answer to match – Will Jul 02 '15 at 16:44
  • Thanks for the update, unfortunately the optional can't be unwrapped with this command either. The error is the same... – beeb Jul 04 '15 at 16:01
  • May I add that I imported AppKit and that I don't understand why the currentContext() can't be unwrapped. Is there something specific to do, before that, to specify what the current context should be? I also tried the following `let contextPointer = NSGraphicsContext.currentContext()!.graphicsPort; let context = unsafeBitCast(contextPointer, CGContext.self)` but no luck either. Here's the full code http://swiftstub.com/126897506/?v=gm – beeb Jul 10 '15 at 10:11