I'm to trying to display an umlaut mark on an i in my CoreGraphics function: ï.
I tried to use it's unicode representation (ï), but I don't manage to get it right.
here is my code:
void drawColorString(CGContextRef ctx, NSString *text, UIColor *color, CGPoint pos){
CGContextSaveGState(ctx);
[color setFill];
CGContextSelectFont(ctx, "Georgia-BoldItalic", 14, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGAffineTransform xform = CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
CGContextSetTextMatrix(ctx, xform);
CGContextShowTextAtPoint(ctx, pos.x, pos.y, [text UTF8String], text.length);
CGContextRestoreGState(ctx);
}
it works very well for regular strings, but I get a square for each special char...
Can anyone help me?
Thanks.
R.
Drawing text in Quartz sucks. One reason is that it doesn't support Unicode: Your choices are plain old ASCII and MacRoman. You might be able to do it by looking up the glyphs for the characters, but that's not fun at all and I bet there are some easy ways to get it wrong.
You can draw a ï in MacRoman easily enough, but a far better solution is to switch to Core Text.
Related
When drawing using CoreGraphics to draw a string/label we have 2 methods
- (CGSize)drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(NSLineBreakMode)lineBreakMode alignment:(NSTextAlignment)alignment;
eg:
[value drawInRect:CGRectMake(xValue, rect.origin.y, objLegends.value *singleUnitWidth,heightOfBar)
withFont:[UIFont systemFontOfSize:10.0f]
lineBreakMode:NSLineBreakByClipping
alignment:NSTextAlignmentCenter];
and
CG_EXTERN void CGContextShowText(CGContextRef c, const char *string,
size_t length) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
eg
CGContextSaveGState(context);
// Tanslate and scale upside-down to compensate for Quartz's inverted coordinate system
CGContextSetTextMatrix(context, CGAffineTransformMake(1.0,0.0, 0.0, -1.0, 0.0, 0.0));
CGContextSelectFont(context, "Helvetica", 10.0f, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetTextPosition(context, xValue, rect.size.height-heightOfText);
if ([value canBeConvertedToEncoding:NSMacOSRomanStringEncoding])
{
CGContextShowText(context, [value cStringUsingEncoding:NSMacOSRomanStringEncoding],5);
// strlen([value cStringUsingEncoding:NSMacOSRomanStringEncoding]));
}
CGContextRestoreGState(context);
Which one is a good method and why?
The best method is the one that is simplest to achieve your goal. The higher the level of API you can use the better. If you can use the NSString method then you should - unless you can use UILabel (or similar) to do the job for you. Always try to write the least code possible and reuse code that's provided for you, dropping to use lower level API if your requirements or performance profiling show you need to.
I have been trying to underline a multiline label but I am not able to do that.
I have referred to this link but this doesn't seem to help me.
How can be done without using NSAttributedString and coreText?
You could use some of these open source projects from GitHub which are like UILabel's but support an attributed string:
TTTAttributedLabel or OHAttributedLabel
Following steps can be helpful.
Extend UILable OR UIView.
Implement - (void)drawRect:(CGRect)rect
In that method get context using `CGContextRef ctx = UIGraphicsGetCurrentContext();
Set text you want to set using this.
CGContextSetRGBFillColor(context,1.0, 0.0, 0.0, 1.0);
CGContextSetTextMatrix(context,CGAffineTransformMakeTranslation(0,pageSize.height));
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSelectFont(context, "Helvetica", 30, kCGEncodingMacRoman);
char *str=(char*)[#"TEXT" UTF8String];
CGContextShowTextAtPoint(context,476/2-200,673/2+100,str,strlen(str));
Set Line using this code.
CGContextSetLineWidth(ctx, 3);
Draw line using this code.
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, thisX, thisY);
CGContextAddLineToPoint(ctx, thatX,thatY);
CGContextStrokePath(ctx);
Hope above collected segments of code helps you....
I am creating sub class for UILabel to adjust the character spacing. It works well.
But when I use special characters as in Spanish or Japanese language, its not writing. Only english characters are written properly. Any solution on how to display them?
- (void) drawRect:(CGRect)rect
{
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSUTF8StringEncoding], self.font.pointSize, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, -1);
CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
CGAffineTransform myTextTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1.f, -1.f );
CGContextSetTextMatrix (context, myTextTransform);
// draw 1 but invisbly to get the string length.
const char* str = [self.text UTF8String];
CGPoint p = CGContextGetTextPosition(context);
float centeredY = (self.font.pointSize + (self.frame.size.height - self.font.pointSize)/2)-2;
CGContextShowTextAtPoint(context, 0, centeredY, str, [self.text length]);
CGPoint v = CGContextGetTextPosition(context);
float centeredX = 0;
if (self.centered) {
float width = v.x - p.x;
centeredX = (self.frame.size.width- width)/2;
}
// calculate width and draw second one.
CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
CGContextShowTextAtPoint(context, centeredX, centeredY, str, [self.text length]);
}
CGContextShowTextAtPoint does not directly support those languages -- the MacRoman encoding may have been a hint. CG has only basic text layout/drawing.
two alternatives would be Cocoa's text drawing, or CoreText.
Better late than never;
Use CoreText to drawFonts instead (Special characters and Unicode)
http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_text/dq_text.html#//apple_ref/doc/uid/TP30001066-CH213-TPXREF101
"iOS 3.2 and later and Mac OS X both support Core Text, an advanced low-level technology for laying out text and handing fonts. Core Text is designed for high performance and ease of use and allows you to draw Unicode text directly to a graphics context. If you are writing an application that needs precise control over how text is displayed, see Core Text Programming Guide."
I am working on an app where I am using CGContextShowTextAtPoint to display text to the screen. I want to also display Japanese characters, but CGContextShowTextAtPoint takes as its input a C string. So either A) How do I change Japanese characters into a C string? If this is not possible, B) How can I manually print Japanese characters to the screen (within the drawRect method).
Thanks in advance.
CoreText can help you:
CTFontGetGlyphsForCharacters (iOS 3.2 onwards) maps Unicode characters to glyphs
CTFontDrawGlyphs (iOS 4.2 onwards) draws the glyphs into a CGContext.
NB. CGContextShowGlyphs should work, but I never found a way to convert my UniChars to glyphs. More on that here:
Ancient, pre iOS 3.2 answer
you need to use UIKit for this.
Check out [NSString drawAtPoint:...] to get started.
This SO question is useful, too.
I don't know what they were thinking with the CoreGraphic text stuff, it's useless.
I was able to get this working by using a reimplementation of CGFontGetGlyphsForUnichars by Jens Egeblad: GlyphDrawing.mm
First load in a Japanese font as an otf file from the app bundle:
// Load font file from otf file
NSString *fontPath = [[NSBundle mainBundle] pathForResource:#"HStdNW8" ofType:#"otf"];
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithFilename([fontPath UTF8String]);
CGFontRef _cgFont = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
Then you can convert your unichar text to glyphs and draw them:
NSString *text = #"日本語"
CGContextSetFont(context, _cgFont);
CGContextSetFontSize(context, 12);
CGGlyph textGlyphs[[text length]];
unichar textChars[[text length]];
for(int i = 0; i < [text length]; i++) {
textChars[i] = [text characterAtIndex:i];
}
CMFontGetGlyphsForUnichars(_cgFont, textChars, textGlyphs, [text length]);
CGContextShowGlyphsAtPoint(context, xCoord, yCoord, textGlyphs, [text length]);
For what it's worth, I spent a long time trying to get Japanese characters to work well in CoreGraphics, and didn't like where it left me.
In the end I switched to using UILabels to handle the text. All the CoreGraphics-like stuff I needed could be replicated using the transform & animation support, and in the end the resulting code was much simpler.
It may not be appropriate for your situation, but it's worth considering.
This maybe helps you %topic starter%. Thanks to Rhythmic Fistman for great advice!
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSelectFont (context, [self.font.fontName cStringUsingEncoding:NSASCIIStringEncoding], self.font.pointSize, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(context, characterSpacing);
CGContextSetFillColorWithColor(context, [self.textColor CGColor]);
CGAffineTransform myTextTransform = CGAffineTransformScale(CGAffineTransformIdentity, 1.f, -1.f );
CGContextSetTextMatrix (context, myTextTransform);
CGGlyph glyphs[self.text.length];
CTFontRef fontRef = CTFontCreateWithName((CFStringRef)self.font.fontName, self.font.pointSize, NULL);
CTFontGetGlyphsForCharacters(fontRef, (const unichar*)[self.text cStringUsingEncoding:NSUnicodeStringEncoding], glyphs, self.text.length);
float centeredY = (self.font.pointSize + (self.frame.size.height- self.font.pointSize)/2)-2;
CGContextShowGlyphsAtPoint(context, rect.origin.x, centeredY, (const CGGlyph *)glyphs, self.text.length);
CFRelease(fontRef);
I am attempting to fill some text with a gradient-fill, where by I set the text drawing mode to clipping, and then paint a gradient-fill.
The problem is, whenever I set the text drawing mode to clip, every character of the text string is placed on top of each other, rather than being painted in a sequence to form a word - it is most bizarre!
My code looks like this:
CGRect r = CGRectInset(self.frame, 55, 8);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat components[8] = {44/255, 54/255, 66/255, 1.0
,75/255, 92/255, 111/255, 1.0};
CGFloat locations[2] = {0, 1};
// draw the text's gradient fill
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
CGContextSetTextDrawingMode(context, kCGTextClip);
[monthString drawInRect:r withFont:f lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter];
CGContextFillRect(context, CGRectMake(0, 0, 320, 20));
It appears that the UIKit NSString additions that let you do drawInRect:withFont: and the like don't play well with the kCGTextClip drawing mode. I've seen the same behavior, and in this answer I provide code to fill text with a gradient using pure Quartz drawing calls. The downside to this approach is that you are limited to the MacRoman text encoding, which lacks support for many Unicode symbols.