1

I'm using TextKit to get something like the following example (first image): a text (attributedString) placed into an area defined by using BezierPath as set as ExclusionPaths to NSTextContainer. The orange area is the excluded area, so the text will only be drawn into the blue area.

displayed text

So far so good. My question is, how can I draw the text to an image as shown? So I have an image with a transparent background and text only, like this:

transparent image with text only

Has anyone an idea how to achieve this?

Dirk
  • 2,011
  • 1
  • 20
  • 25
  • So, isn't this simply about _how to draw into an image_ or _how to generate an image_? If so, this been been answered lots of time here already. – DarkDust Aug 05 '14 at 21:46
  • @DarkDust you are right, it's easy to draw text into image if it's a simple shape like a rectangle, but it seems to be tricky to draw text into an image by using an individual shape defined by the BezierPath... – Dirk Aug 05 '14 at 21:56
  • If you're trying to create an image from text already on the screen, you could look at rendering a view/layer to a CGImage. – Brian Nickel Aug 05 '14 at 22:00

1 Answers1

2

It looks like you are trying to implement an editor where users can enter text and then generate a final image. If that's the case, you can have the text view draw directly into your graphics context by finding the layer with text and having it draw onto your current context:

[layerWithText drawInContext:UIGraphicsGetCurrentContext()];

Through experimentation, I found that layerWithText == textView.layer.sublayers[0] on iOS8. Since you're in private space though, you cannot guarantee that configuration between iOS versions. A slightly better version would be the following, though it assumes the layer and all sublayers are at the same position with no transformations. My recommendation would be to just watch that nothing breaks when new versions come out.

- (void)drawLayer:(CALayer *)layer recursivelyInContext:(CGContextRef)context
{
    [layer drawInContext:context];
    for (CALayer *sublayer in layer.sublayers) {
        [self drawLayer:sublayer recursivelyInContext:context];
    }
}

This will of capture the background of the text view if not transparent, so you may want to do the following if that is the case:

UIColor *originalBackgroundColor = textView.backgroundColor;
textView.backgroundColor = [UIColor clearColor];
[self renderLayer:textView.layer recursivelyInContext:UIGraphicsGetCurrentContext()];
textView.backgroundColor = originalBackgroundColor;

Example project: https://github.com/bnickel/SO25148857

Note: I had originally suggested renderInContext: as this renders the view's layer and all sublayers. This unfortunately appears to present a cached rasterization of the layer hierarchy. drawInContext: in contrast renders a single layer but forces a fresh drawing.

Brian Nickel
  • 26,890
  • 5
  • 80
  • 110
  • Thank you @BrianNickel it works (additionally I disabled editing and correction to avoid unwanted elements). But compared with text drawn directly there is a clear lack of quality. I already use `UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0f);` to set the scale factor of the device’s main screen, so as far as I understood I get the best possible quality for this way. This could be a good temporarily solution for me, but I hope someone may provide the answer to my original question. – Dirk Aug 05 '14 at 22:53
  • @Dirk: Text rendered onto a transparent background in an image cannot use sub-pixel antialiasing, so it will always look a tad worse than when rendered onto a solid surface or a view. You might want to experiment with some of the [CoreGraphics settings](http://stackoverflow.com/questions/14442498/coretext-font-smoothing-on-a-transparent-background) (might want to have a property to switch these workarounds on when rendering into an image). – DarkDust Aug 06 '14 at 06:57
  • @DarkDust I've played around with the CoreGraphics settings, but without any effect :o/ Nevertheless, thank you. – Dirk Aug 06 '14 at 14:43
  • @Dirk I've updated the answer with a working approach and an example project. – Brian Nickel Aug 06 '14 at 21:59