I need to create an image containing one line of text. But the problem, i first need to create the context (CGBitmapContextCreate) with require the width and the height of the image to have the possibility to later calculate the bounds of the text (via CTLineGetImageBounds). but i want the size of the image = the bounds of the text :( how can i do ?
actually i use
CGBitmapContextCreate CTLineGetImageBounds CTLineDraw
maybe it's possible to call CTLineGetImageBounds without a context ?
Note: i m on delphi, it's not really a problem as i can have access to all the API, i just need the function name
6 Answers
Answers 1
You can calculate the space an NSString
will take up based on the font you want to use by doing the following:
NSString *testString = @"A test string"; CGSize boundingSize = self.bounds.size; CGRect labelRect = [testString boundingRectWithSize:boundingSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{ NSFontAttributeName : [UIFont systemFontOfSize:14] } context:nil];
Where bounding size is the maximum size you want the image to be. Then you can use the calculated size to create your image.
Answers 2
There are a couple of ways to calculate a more or less precise bounding box. You can use font metrics, iterate CTRun
s or use cocoa's string drawing API for calculation.
Yet, I want to draw your attention to the problem that this is not generally possible. While the results from above algorithms are sufficient in many cases, there are a couple of scenarios where they are utterly wrong:
- some letters have parts that reach very far out of the metrics defined in the font. Here's an example from Zapfino: a variation of lower case "f". (Green is Text Edit's selection)
- There are effects that reach out of the calculated box. Outline and shadow are just examples. Shadows can have a very far distance and huge blur.
There might be custom text attributes that your algorithm is not aware of.
A text can contain "attachments" (like images, I think emoji are also implemented as attachments). Those have to be taken into account as well.
When I had to solve this problem before, I finally reached the following solution:
- Create a transparent bitmap context at maximum size (in this case a full page).
- Draw the text at the desired position.
- Walk over the bytes that back the context from outside to inside, scanning the first non-transparent pixel along each edge.
- Cut the resulting rectangle using
CGImageCreateWithImageInRect
.
That's utterly slow, but speed was no priority for my use case.
Answers 3
Below code using to calculate the NSString Size based on the font
extension UIFont { func sizeOfString (string: String, constrainedToWidth width: Double) -> CGSize { return NSString(string: string).boundingRectWithSize(CGSize(width: width, height: DBL_MAX), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self], context: nil).size } }
OR Alternatively you could cast it into an NSString
if let ns_str:NSString = str as NSString? { let sizeOfString = ns_str.boundingRectWithSize( CGSizeMake(self.titleLabel.frame.size.width, CGFloat.infinity), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: lbl.font], context: nil).size }
Answers 4
It sounds like you've already done most of the work. You just need to create a temporary context to call CTLineGetImageBounds
against. I believe it's ok for that context to be very small (one pixel, for instance, maybe even zero), and of course you can reuse it. Ideally it should have the same attributes (other than size) as your final context, though even that probably won't matter in most cases. It's only required for its metadata.
Answers 5
OK, i found the solution: use CTLineGetImageBounds(aline, null{context}); simply pass null for the context and it's work as expected ;)
Answers 6
This the could you need to write in order to get the size of the text with the font.
let widthOfLabel = 400.0 let size = font?.sizeOfString(self.viewCenter.text!, constrainedToWidth: Double(widthOfLabel))
You have to use the below extension of the font in order to get the size of the text with the font.
extension UIFont { func sizeOfString (string: String, constrainedToWidth width: Double) -> CGSize { return NSString(string: string).boundingRectWithSize(CGSize(width: width, height: DBL_MAX), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: self], context: nil).size } }
0 comments:
Post a Comment