Iphone CGContextShowTextAtPoint for Japanese characters - iphone

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);

Related

cString fails when given Russian characters on iPhone

I think this is pretty basic. I have the following code which writes text to a file for me:
float curpo = CGContextGetTextPosition(ref).x;
float newpo = 0;
float textw = 0;
const char *text = [userName cStringUsingEncoding:NSUTF8StringEncoding];
CGContextSetTextDrawingMode(ref, kCGTextInvisible);
CGContextShowTextAtPoint (ref, 0, pos, text, strlen(text));
newpo = CGContextGetTextPosition(ref).x;
textw = newpo - curpo;
It works fine with traditional english text, but when I pass in Russian or other cyrillic characters, the text comes out all jumbled. How can I fix this?
For each byte in text, CGContextShowTextAtPoint() is going to map it to a glyph in the CGContextRef's current font. This is at a lower level than you probably want.
To draw a string which may contain any glyphs from any language, use the string drawing methods in UIStringDrawing.h . Something like this:
UIGraphicsPushContext(context);
[userName drawAtPoint:pos withFont:[UIFont systemFontOfSize:16]];
UIGraphicsPopContext();
If you need finer-grain control, you can look at the CoreText frame and create a CFAttributedString from your NSString, then create a CTFramesetterRef via CTFramesetterCreateWithAttributedString(), create a CTFrameRef from that, and draw it to the context using CTFrameDraw().

Display NSAttributedString using CoreText

I have heard that I can display a NSAttributedString using CoreText, can anyone say me how (The simplest way)?
Please, don't answer with CATextLayer or OHAttributedLabel.
I know that there are a lot of questions about this in this forum, but I haven't find the answer
Thanks!!
Simplest way? Something like this:
CGContextRef context = UIGraphicsGetCurrentContext();
// Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// Create a path to render text in
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.bounds );
// An attributed string containing the text to render
NSAttributedString* attString = [[NSAttributedString alloc]
initWithString:...];
// create the framesetter and render text
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, [attString length]), path, NULL);
CTFrameDraw(frame, context);
// Clean up
CFRelease(frame);
CFRelease(path);
CFRelease(framesetter);
I think that the simplest way (using Core Text) is:
// Create the CTLine with the attributed string
CTLineRef line = CTLineCreateWithAttributedString(attrString);
// Set text position and draw the line into the graphics context called context
CGContextSetTextPosition(context, x, y);
CTLineDraw(line, context);
// Clean up
CFRelease(line);
Using a Framesetter is more efficient IF you are drawing lots of text but this is the method recommended by Apple if you just need to display a small amount of text (like a label) and doesn't require you to create a path or frame (since it is done for you automatically by CTLineDraw).
Starting from ios 6 you can do the following :
NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];
[paragrahStyle setLineSpacing:40];
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [labelText length])];
cell.label.attributedText = attributedString ;

iPhone - Using CGContextShowTextAtPoint to draw special characters

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."

Convert pdf file to text file

Hi all I am working on Objective-C. my previous Question was How can I edit PDF files in an iOS application?
after a lot of googling I found out the following. display the pdf in UIWebView, extract the data using C/javascript and edit it. I am still not sure about this procedure. now what I have planned is
1) display the pdf
2) when user wants to edit the pdf I covert the pdf to text and allow him to edit it
3) tryin to save wil convert the content back to pdf.
is this a gud way to proceed?? im k with step 1. now how do i convert pdf--> text and text-->pdf.
thanks in advance
When you load a custom document type (doc, ppt, pdf, etc) into a UIWebView, the webview returns a nil HTML string, even via javascript. There's a few suggestions for extracting PDF text here.
But turning the string back into a PDF is different. If you want to retain the formatting of the original PDF, I'm rather sure that's impossible because NSAttributedString on iOS doesn't do much. But this will work for plain text or NSAttributedString, if its possible:
NSData *PDFDataFromString(NSString *str) {
NSMutableData *data = [NSMutableData data];
//Create an NSAttributedString for CoreText. If you find a way to translate
//PDF into an NSAttributedString, you can skip this step and simply use an
//NSAttributedString for this method's argument.
NSAttributedString* string = [[[NSAttributedString alloc] initWithString:str] autorelease];
//612 and 792 are the dimensions of the paper in pixels. (8.5" x 11")
CGRect paperRect = CGRectMake(0.0, 0.0, 612, 792);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef) string);
CGSize requiredSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, [string length]), NULL, CGSizeMake(paperRect.size.width - 144, 1e40), NULL);
//Subtract the top and bottom margins (72 and 72), so they aren't factored in page count calculations.
NSUInteger pageCount = ceill(requiredSize.height / (paperRect.size.height - 144));
CFIndex resumePageIndex = 0;
UIGraphicsBeginPDFContextToData(data, paperRect, nil);
for(NSUInteger i = 0; i < pageCount; i++)
{
//After calculating the required number of pages, break up the string and
//draw them into sequential pages.
UIGraphicsBeginPDFPage();
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState (currentContext);
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGMutablePathRef framePath = CGPathCreateMutable();
//72 and 72 are the X and Y margins of the page in pixels.
CGPathAddRect(framePath, NULL, CGRectInset(paperRect, 72.0, 72.0));
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, CFRangeMake(resumePageIndex, 0), framePath, NULL);
resumePageIndex += CTFrameGetVisibleStringRange(frameRef).length;
CGPathRelease(framePath);
CGContextTranslateCTM(currentContext, 0, paperRect.size.height);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CTFrameDraw(frameRef, currentContext);
CFRelease(frameRef);
CGContextRestoreGState (currentContext);
}
CFRelease(framesetter);
UIGraphicsEndPDFContext();
return data;
}

CoreGraphic - display umlaut mark on an i

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.