How to draw text in PDF context in Swift? - swift

I have a simple function that create pdf file and return its path.
func createPDFFileAndReturnPath() -> String {
let fileName = "pdffilename.pdf"
let paths = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0]
let pathForPDF = documentsDirectory.stringByAppendingString("/" + fileName)
UIGraphicsBeginPDFContextToFile(pathForPDF, CGRectZero, nil)
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 100, 400), nil)
let text = "text" //how to print this in whatever place?
//text.drawInRect - this doesn't work
UIGraphicsEndPDFContext()
return pathForPDF
}

Here is your function:
func createPDFFileAndReturnPath() -> String {
let fileName = "pdffilename.pdf"
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0] as! NSString
let pathForPDF = documentsDirectory.stringByAppendingString("/" + fileName)
UIGraphicsBeginPDFContextToFile(pathForPDF, CGRectZero, nil)
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 100, 400), nil)
let font = UIFont(name: "Helvetica Bold", size: 14.0)
let textRect = CGRectMake(5, 3, 125, 18)
var paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.alignment = NSTextAlignment.Left
paragraphStyle.lineBreakMode = NSLineBreakMode.ByWordWrapping
let textColor = UIColor.blackColor()
let textFontAttributes = [
NSFontAttributeName: font!,
NSForegroundColorAttributeName: textColor,
NSParagraphStyleAttributeName: paragraphStyle
]
let text:NSString = "Hello world"
text.drawInRect(textRect, withAttributes: textFontAttributes)
UIGraphicsEndPDFContext()
return pathForPDF
}

Sebastian's Answer - Updated for Swift 4.2
func createPDFFileAndReturnPath() -> String {
let fileName = "pdffilename.pdf"
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0] as NSString
let pathForPDF = documentsDirectory.appending("/" + fileName)
UIGraphicsBeginPDFContextToFile(pathForPDF, CGRect.zero, nil)
UIGraphicsBeginPDFPageWithInfo(CGRect(x: 0, y: 0, width: 100, height: 400), nil)
let font = UIFont(name: "System", size: 14.0)
let textRect = CGRect(x: 5, y: 3, width: 125, height: 18)
let paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
paragraphStyle.alignment = NSTextAlignment.left
paragraphStyle.lineBreakMode = NSLineBreakMode.byWordWrapping
let textColor = UIColor.black
let textFontAttributes = [
NSAttributedString.Key.font: font!,
NSAttributedString.Key.foregroundColor: textColor,
NSAttributedString.Key.paragraphStyle: paragraphStyle
]
let text:NSString = "Hello world"
text.draw(in: textRect, withAttributes: textFontAttributes)
UIGraphicsEndPDFContext()
return pathForPDF
}

Related

How to calculate boundRect correctly for NSAttributedString When apply shadow

I tried apply shadow effect to UILabel using NSAttributeString. I want to change the size of UILabel whenever change shadow offset. However, it doesn't calculate correct frame and ignore shadow offset. How can I achieve?
let textView = UILabel(frame: CGRect(x: 20, y: 100, width: 300, height: 50))
textView.layer.borderColor = UIColor.red.cgColor
textView.layer.borderWidth = 1
textView.numberOfLines = 0
textView.text = "hyHgjpQ\nhyHgjpQ\nhyHgjpQ"
textView.font = UIFont(name: "DamascusSemiBold", size: 40)
textView.textColor = .white
textView.textAlignment = .center
self.view.addSubview(textView)
var textAttributes: [NSAttributedString.Key: AnyObject] = [:]
// font name & size
let font = UIFont(name: "HelveticaNeue", size: 50)
textAttributes[NSAttributedString.Key.font] = font
// shadow
let shadow = NSShadow()
shadow.shadowBlurRadius = 10
shadow.shadowOffset = CGSize(width: 10, height: 30)
shadow.shadowColor = UIColor.red
textAttributes[NSAttributedString.Key.shadow] = shadow
textView.attributedText = NSAttributedString(string: textView.text ?? "", attributes: textAttributes)
let bound = textView.text!.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: textAttributes,
context: nil)
textView.bounds = bound
Result

MacOS: Add a text overlay to an image in Swift

I've written a small extension for UIImage, which adds a text to an image:
extension UIImage {
func addTextToImage(textToAdd: String) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Snell Roundhand", size: 40)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(self.size, false, scale)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.center
var textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
NSAttributedString.Key.paragraphStyle: paragraphStyle
] as [NSAttributedString.Key : Any]
self.draw(in: CGRect(origin: CGPoint.zero, size: self.size))
let textFrame = CGPoint(x: self.size.width/4, y: self.size.height/4)
let rect = CGRect(origin: textFrame, size: CGSize(width: self.size.width/2, height: self.size.height/2) )
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
The result should look like this:
Now I want to do the same thing for NSImage to run on MacOS.
Any ideas how to do this?
All similar questions on Stackoverflow are either very old, unanswered or in Objective C
Found a solution:
extension NSImage {
func addTextToImage(drawText text: String) -> NSImage {
let targetImage = NSImage(size: self.size, flipped: false) { (dstRect: CGRect) -> Bool in
self.draw(in: dstRect)
let textColor = NSColor.white
let textFont = NSFont(name: "Snell Roundhand", size: 36)! //Helvetica Bold
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = NSTextAlignment.center
var textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
] as [NSAttributedString.Key : Any]
let textOrigin = CGPoint(x: self.size.height/3, y: -self.size.width/4)
let rect = CGRect(origin: textOrigin, size: self.size)
text.draw(in: rect, withAttributes: textFontAttributes)
return true
}
return targetImage
}
}

How to create random string with multiple formats?

I need to create a random string with format which can convert any string(including parenthesis() to another color on swift: for example:
Hey (Hey) : First part 'Hey' is fine, but I want to change : (Hey) to a different color
same goes if I choose another string
Hi (What's Up) ....
And tried the following
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
let color = UIColor(white: 0.2, alpha: 1)
let attributedTextCustom = NSMutableAttributedString(string: "(\(String())", attributes: [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: color]))
attributedTextCustom.append(NSAttributedString(string: " (\(String())", attributes: [.font: UIFont(name: "AvenirNext-Regular", size: 12)!, .foregroundColor: UIColor.lightGray]))
label.attributedText = attributedTextCustom
Something like this is the behavior I am looking for (just for demostration...):
You can use a regex "\\((.*?)\\)" to find the range of the word between the parentheses and add the color attribute to a NSMutableAttributedString:
let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 200, height: 50)))
let sentence = "Hello (Playground)"
let mutableAttr = NSMutableAttributedString(string: sentence, attributes: [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: UIColor.black])
if let range = sentence.range(of: "\\((.*?)\\)", options: .regularExpression) {
let color = UIColor(white: 0.2, alpha: 1)
let attributes: [NSAttributedString.Key: Any] = [.font: UIFont(name:"AvenirNext-Medium", size: 16)!, .foregroundColor: color]
mutableAttr.addAttributes(attributes, range: NSRange(range, in: sentence))
label.attributedText = mutableAttr
}

Clipped text on UILabel

I'm using custom a font for UILabel but there is a strange problem, for some characters the text is being clipped:
The label should be like this (label frame has enlarged manually):
This is the code to add the label to the gray view:
let string = "کیخسروی"
let font = UIFont(name: "IranNastaliq", size: 30)!
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byWordWrapping
paragraphStyle.alignment = .center
let attributes: [NSAttributedStringKey: Any] = [
.font: font,
.paragraphStyle: paragraphStyle
]
let mutabbleAttributedString = NSMutableAttributedString(string: string, attributes: attributes)
let rectSize = mutabbleAttributedString.size()
let label = UILabel(frame: CGRect(x: 0, y: 0, width: rectSize.width, height: rectSize.height))
label.font = font
label.attributedText = mutabbleAttributedString
label.backgroundColor = UIColor.yellow
label.textAlignment = .center
let size = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
let width = label.sizeThatFits(size).width
let height = label.sizeThatFits(size).height
let frame = CGRect(x: 0, y: 0, width: width, height: height)
label.frame = frame
self.myView.addSubview(label)
label.center = self.myView.center
Seems sizeThatFits() does not calculate the bounds correctly.
I have to mention this clipping only happens while using some custom fonts.

How do you set an Attributed Title Color for State in Swift

I'm able to set the attributedTitle for a UIControlState, but how would I set the attributed title's color for a UIControlState?
// create the button
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.backgroundColor = UIColor.yellowColor()
// set the attributed title for different states
// .Selected
let mySelectedAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSForegroundColorAttributeName : UIColor.greenColor()])
button.setAttributedTitle(mySelectedAttributedTitle, forState: .Selected)
// .Normal
let myNormalAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSForegroundColorAttributeName : UIColor.blueColor()])
button.setAttributedTitle(myNormalAttributedTitle, forState: .Normal)
Swift 4 & 5
// create the button
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.backgroundColor = UIColor.yellow
// set the attributed title for different states
// .Selected
let mySelectedAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSAttributedStringKey.foregroundColor : UIColor.green])
button.setAttributedTitle(mySelectedAttributedTitle, for: .selected)
// .Normal
let myNormalAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSAttributedStringKey.foregroundColor : UIColor.blue])
button.setAttributedTitle(myNormalAttributedTitle, for: .normal)
Swift 3
// create the button
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
button.backgroundColor = UIColor.yellow
// set the attributed title for different states
// .Selected
let mySelectedAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSForegroundColorAttributeName : UIColor.green])
button.setAttributedTitle(mySelectedAttributedTitle, for: .selected)
// .Normal
let myNormalAttributedTitle = NSAttributedString(string: "Click Here",
attributes: [NSForegroundColorAttributeName : UIColor.blue])
button.setAttributedTitle(myNormalAttributedTitle, for: .normal)
Swift 5 functions to set the color and font.
class func setButtonTextColor( _ button:UIButton , color:UIColor ) {
if let str = button.titleLabel?.attributedText {
let attributedString = NSMutableAttributedString( attributedString: str )
attributedString.removeAttribute(.foregroundColor, range: NSRange.init(location: 0, length: attributedString.length))
attributedString.addAttributes(
[NSAttributedString.Key.foregroundColor : color],
range: NSRange.init(location: 0, length: attributedString.length)
)
button.setAttributedTitle(attributedString, for: .normal)
}
}
class func setButtonTextFont( _ button:UIButton, font: UIFont) {
if let str = button.titleLabel?.attributedText {
let attributedString = NSMutableAttributedString( attributedString: str )
attributedString.removeAttribute(.font, range: NSRange.init(location: 0, length: attributedString.length))
attributedString.addAttributes(
[NSAttributedString.Key.font : font ],
range: NSRange.init(location: 0, length: attributedString.length)
)
button.setAttributedTitle(attributedString, for: .normal)
}
}