I'm trying to draw text with some part of it in different color
First issue it that when using the following code:
NSMutableAttributedString *test1 = [[NSMutableAttributedString alloc] initWithString:#"fi"];
// Should color only the first character "f"
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(0, 1)];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test1);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));
CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);
And then drawing the frame:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
// Flip the coordinate system
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw(textFrame, context);
CGContextRestoreGState(context);
For some reason it shows both "f" and "i" colored in red. When I change the text to "f1" , "f!", or anything else it works OK. Even when I use "afi" and range as (1,1) it colors both "f" and "i" as if it treats it as a single character.
Second issue, when drawing inside a frame with width which is less that the width of the text:
NSMutableAttributedString *test2 = [[NSMutableAttributedString alloc] initWithString:#"aaaaaaaaaaaaaaaaaaaa"];
CTLineBreakMode lineBreakMode;
lineBreakMode = kCTLineBreakByTruncatingTail;
// Apply selected truncation
CTParagraphStyleSetting paragraphStyleSetting = {kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreakMode};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(¶graphStyleSetting, 1);
[test1 addAttribute:(NSString *)kCTParagraphStyleAttributeName value:(__bridge id)paragraphStyle range:NSMakeRange(0, test2.string.length)];
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(7, 16)];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test2);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));
CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);
There are total 20 characters,
the ones at indexes 7 to 16 appear colored in red (as they should), CoreText adds a truncation mark as I requested but the problem is that it colored in red too and I want it to remain black (as the remaining truncated characters color is black).
I did some study and it seems that when increasing the frame size by some (random/font specific?) value in the command:
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width + 10.0f, self.frame.size.height));
It keeps the truncation mark black, but because of the extra space sometimes the truncation mark is clipped
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:#"firstsecondthird"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,5)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(5,6)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(11,5)];
This sounds like an issue with ligatures. A good font has special characters for some combinations of characters that look better than the individual characters. For example, in a lot of fonts To doesn't look good if rendered individually since there's a lot of space between the vertical bar of T and the start of the o. So ligatures are provided that have a more appealing spacing. Sometimes the characters even get connect, your fi is a good example: some fonts provide a ligature that makes the top of the f double as the dot for the i.
So you may want to turn the ligatures off but setting the attribute kCTLigatureAttributeName to 0.
Related
In iOS7 CGContextSelectFont is deprecated. Deprecation message says that I have to use Core Text, but I don't know which is the exact equivalent of this piece of code:
CGContextSelectFont(context, "Helvetica", kBarLabelSize, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetRGBFillColor(context, 0, 0, 0, 1.0);
CGContextSetTextMatrix (context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0));
CGContextShowTextAtPoint(context, barX, barY, [#"Some text" cStringUsingEncoding:NSUTF8StringEncoding], [barValue length]);
I've been able to create the font with this code:
CFMutableAttributedStringRef attrStr = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica"), kBarLabelSize, NULL);
CFAttributedStringSetAttribute(attrStr, CFRangeMake(0, CFAttributedStringGetLength(attrStr)), kCTFontAttributeName, font);
But now haw can I "draw" a text with this font into the context?
As best I can understand from your code, the exact equivalent is:
CGContextSetTextDrawingMode(context, kCGTextFill); // This is the default
[[UIColor blackColor] setFill]; // This is the default
[#"Some text" drawAtPoint:CGPointMake(barX, barY)
withAttributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica"
size:kBarLabelSize]
}];
Note that your calls to CGContextSetTextDrawingMode and CGContextSetRGBFillColor are setting the values to the defaults. Your call to CGContextSetTextMatrix is not needed when using UIKit drawing like this.
I have no idea what [barValue length] is here, however. I'm assuming that you simply incorrectly used this for the length of #"Some text". (length is not the number of bytes which is what you need. What you probably meant was [barValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]).
Note that UIKit string drawing (seen here) wraps Core Text.
I have found, at least in my case, the problem with the new NSString.drawAtPoint interface is that it may draw upside down, depending on how you are using the context.
An alternate is to use the Core Text methods, specifically the CTLine interface thusly:
NSDictionary *attribs = #{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:14.0]};
NSAttributedString *fontStr = [[NSAttributedString alloc] initWithString:#"some text" attributes:attribs];
CTLineRef displayLine = CTLineCreateWithAttributedString( (__bridge CFAttributedStringRef)fontStr );
CGContextSetTextPosition( ctx, xPosition, yPosition );
CTLineDraw( displayLine, ctx );
CFRelease( displayLine );
You probably can use the following to replace it.
CGContextSetFont
CGContextSetFontSize
I am trying to do this:
so I am using this code:
[self.lblRound setOutlineColor:[UIColor colorWithRed:(68/255.0) green:(82/255.0) blue:(120/255.0) alpha:1]];
self.lblRound.drawOutline = YES;
but this is what i get:
I also did try this code:
lblRound.shadowColor = [UIColor colorWithRed:(68/255.0) green:(82/255.0) blue:(120/255.0) alpha:1];
lblRound.shadowOffset = CGSizeMake(0, 0);
I also did try to make another label with the needed color and to draw it behind the text, but if I am playing with the size of the text, it influence on the width of the all text.
How can I make the stroke thicker?
I can't use an image because I have a number in this text that should be variable.
Thanks
This is the solution:
- (void)drawRect:(CGRect)rect
{
UIFont *font=[UIFont fontWithName:#"VAGRoundedStd-Bold" size:40];
CGContextRef context = UIGraphicsGetCurrentContext();
string = lblRoundnumber;
CGSize fontWidth = [string sizeWithFont:font];
CGRect tempRect=rect;
tempRect.origin.x +=160-(fontWidth.width/2);
tempRect.origin.y +=high+42;
CGContextSetRGBStrokeColor(context, 68/255.0f, 82/255.0f, 120/255.0f, 1/1.0f);
CGContextSetRGBFillColor(context, 68/255.0f, 82/255.0f, 120/255.0f, 1/1.0f);
CGContextSetTextDrawingMode(context, kCGTextStroke);
CGContextSetLineWidth(context, 11);
[string drawInRect:tempRect withFont:font];
CGContextSetRGBFillColor(context, 1,1,1,1);
CGContextSetTextDrawingMode(context, kCGTextFill);
[string drawInRect:tempRect withFont:font];
}
If I create a PDF using core text framework, it will not allow me to set color and font style.
Is there any problem with "core text" framework?
I am using below code for setting color :
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(currentContext, 1.0, 0.0, 0.0, 1.0); //This is not working.
Try below code, in this code i've changed my font style and size with CTFontRef
+(void)drawText:(NSString*)textToDraw inFrame:(CGRect)frameRect
{
CFStringRef stringRef = ( CFStringRef)textToDraw;
CGColorSpaceCreateWithName(stringRef);
NSMutableAttributedString *string = [[NSMutableAttributedString alloc]
initWithString:textToDraw];
CTFontRef helveticaBold;
helveticaBold = CTFontCreateWithName(CFSTR("Helvetica-Bold"), 24.0, NULL);
[string addAttribute:(id)kCTFontAttributeName
value:(id)helveticaBold
range:NSMakeRange(0, [string length])];
[string addAttribute:(id)kCTForegroundColorAttributeName
value:(id)[UIColor whiteColor].CGColor
range:NSMakeRange(0, [string length])];
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
CFRange currentRange = CFRangeMake(0, 0);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGContextTranslateCTM(currentContext, 0, frameRect.origin.y*2);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CTFrameDraw(frameRef, currentContext);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CGContextTranslateCTM(currentContext, 0, (-1)*frameRect.origin.y*2);
CFRelease(frameRef);
CFRelease(string);
CFRelease(framesetter);
}
you can follow this Link also
Example
Hope this helps you, Happy Coding
You can create color object like this:
UIColor *colour = [UIColor colorWithRed:0 green:1 blue:0 alpha:0];
And fill colour:
CGContextSetFillColorWithColor(ctx, colour.CGColor);
If you are not using ARC, you need to retain and release color appropriately.
In my i want to i'm displaying a text in text view.Also i want to change the color of some sentences in that text.When i'm using the code below i'm getting the error NSForegroundColorAttributeName undeclared and i also tried using kCTForegroundColorAttributeNamevalue but is also showing undeclared error.How to remove this error.Can any one help me please.
enter code here
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:#"Paint a picture together, alternating every minute (use a timer to keep track)"];
[string addAttribute:kCTForegroundColorAttributeNamevalue:[UIColor redColor] range:NSMakeRange(0,8)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(8,10)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(10,5)];
On iOS its a PITA...
Here is how I am making a white color and applying it to a range
First
#import <Foundation/NSAttributedString.h>
Then
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components[4] = {1.0f, 1.0f, 1.0f, 1.0f};
CGColorRef whiteColor = CGColorCreate(colorSpace, components);
CGColorSpaceRelease(colorSpace);
[mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(__bridge id)whiteColor range:titleRange];
CGColorRelease(whiteColor);
I happen to be using ARC, so take out the __bridge if you have to.
You need to import CoreText/CoreText.h to get the declaration of kCTForegroundColorAttributeName.
The value must be a CGColor, not a UIColor.
There's less casting to do this way:
CFAttributedStringSetAttribute((__bridge void*)string, CFRangeMake(0, 8),
kCTForegroundColorAttributeName, [UIColor redColor].CGColor);
Have you imported the AppKit framework? Also, include NSAttributedString.h in your header file.
I am searching about drawing bordered text on UIView.
Implemented following method :
- (void)drawRect:(CGRect)rect {
//TODO draw bordered text here.
}
How to draw it ?
I mean each letter is bordered of whole text.
Thanks in advance.
To display bordered text (if I understand correctly what you want) you should set text drawing mode to kCGTextFillStroke (and set appropriate values for text drawing parameters, such as stroke and fill colors etc)
// Choose appropriate text font
CGContextSelectFont(context, [[UIFont boldSystemFontOfSize:24].fontName UTF8String], (int)fontSize, kCGEncodingMacRoman);
// Set text drawing mode
CGContextSetTextDrawingMode(context, kCGTextFillStroke);
// Set appropriate color/line width values
// Here we're set to draw white letters with black border
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
CGContextSetRGBFillColor(context, 1, 1, 1, 1);
CGContextSetLineWidth(context, 1);
// Set this transformations or text will be displayed upside-down
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(context, xform);
// Display text
CGContextShowTextAtPoint(...);
Edit: As Quartz does not work well with unicode, to draw unicode strings you'll need to use other APIs. I managed to draw "bordered" unicode string using NSAttributedString and OHAttributedLabel (thanks to this answer for that custom control). Sample code to get required string in some view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableAttributedString *s = [[NSMutableAttributedString alloc] initWithString:#"您好世界"];
[s addAttributes:[NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:-3.0f] forKey:(NSString*)kCTStrokeWidthAttributeName]
range:NSMakeRange(0, [s length])];
[s addAttributes:[NSDictionary dictionaryWithObject:(id)[UIColor greenColor].CGColor forKey:(NSString*)kCTStrokeColorAttributeName]
range:NSMakeRange(0, [s length])];
[s addAttributes:[NSDictionary dictionaryWithObject:(id)[UIColor redColor].CGColor forKey:(NSString*)kCTForegroundColorAttributeName]
range:NSMakeRange(0, [s length])];
[s setFont:[UIFont boldSystemFontOfSize:28.0f]];
[s setTextColor:[UIColor redColor]];
OHAttributedLabel *l = [[OHAttributedLabel alloc] initWithFrame:CGRectMake(40.0f, 40.0f, 200.0f, 80.0f)];
l.centerVertically = YES;
[l setAttributedText: s];
[self.view addSubview: l];
[l release];
}
Note that you'll need to link with CoreText.framework to make that work, and code uses some convenience methods provided in OHAttributedLabel implementation
I tried this way:
draw with NSString drawAtPoint:withFont: or drawInRect:withFont:
set line joint and lin cap to round.
draw your text with the border color using drawing mode kCGTextStroke, be sure to set the line width a little wider,
then draw your text with its inner color using drawing mode kCGTextFill.
may be you need a little adjustment in the position to make it perfect.