6

I'm working on an application that requires arabic text to be displayed, using custom arabic font. The problem is that i'm not having any luck in displaying the arabic text using custom arabic fonts. I've tried to display the text in UILabel, UITextField, UITextView, UIWebView, FontLabel (by Zynga), and using CoreText.

You can find sample projects here:

Sample application using UILabel, UITextField, UITextView and CoreText

Sample application using UIWebView (HTML)

Sample application using UIWebView (HTML): You'll have to install the fonts in the sample project. You can then compare the results and see the problem by running the application in the simulator (or iPad), and opening Sample.html file in the browser (Safari).

I've posted some details on Apple's developer forum but i've always found stackoverflow to be much more active then Apple's official developer forum. Here's a link to that post:

Using custom arabic font in iOS

What am i doing wrong?

Note: The fonts are loaded into the system correctly, and i can successfully apply custom fonts to regular (english) text.

p.s. There are a couple of posts on stackoverflow that talk about this subject but none have been of much help, so i'm posting a new question.

ataravati
  • 8,891
  • 9
  • 57
  • 89
Mustafa
  • 20,504
  • 42
  • 146
  • 209
  • I've tried bunch of different fonts. You can see some in the projects i've attached. Any particular font you want me to try? – Mustafa Sep 16 '11 at 10:27
  • Any help guys? I think there are no other websites left that I've googled and read. None of the solutions work except MPPersianFont API, which is not so efficient in resource usage. I really need custom arabic/persian fonts... :( – Neeku Jul 14 '12 at 10:55
  • @Neeku, Core Text worked for me. Try that. – Mustafa Jul 16 '12 at 11:11
  • @Mustafa Your dropbox link doesn't seem to be working anymore. Do you have an updated link? – Yazid Aug 02 '13 at 23:09
  • @Yazid Since the issue was resolved, I deleted the project showing the issue. Directly refer to the solution below. – Mustafa Aug 05 '13 at 09:17

5 Answers5

8

Update:

As of iOS 7, you don't really need to use Core Text to render custom arabic font. You can use UILabel and/or UITextView with NSAttributedString. The results are the same as you get using Core-Text. However, depending on your requirements, using Core Text can still be a better option.

Update:

I've reported this as a bug to Apple, but i'm not sure when they'll add support for Arabic fonts. Currently, there's no easy way to do it. I ended up using the default system font, which is not very good.

Original Message

I did managed to build a Quran application that uses custom arabic font. I used known arabic font(s) with Core Text framework to get the desired results. You can see the results I got in the end by checking the application Quran Presenter for iPad, which is available on the App Store.

Here's some sample code to help you out:

- (CTFontRef)newCustomFontWithName:(NSString *)aFontName
                            ofType:(NSString *)type
                        attributes:(NSDictionary *)attributes {
    NSString *fontPath = [[NSBundle mainBundle] pathForResource:aFontName ofType:type];

    NSData *data = [[NSData alloc] initWithContentsOfFile:fontPath];
    CGDataProviderRef fontProvider = CGDataProviderCreateWithCFData((CFDataRef)data);
    [data release];

    CGFontRef cgFont = CGFontCreateWithDataProvider(fontProvider);
    CGDataProviderRelease(fontProvider);

    CTFontDescriptorRef fontDescriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)attributes);
    CTFontRef font = CTFontCreateWithGraphicsFont(cgFont, 0, NULL, fontDescriptor);
    CFRelease(fontDescriptor);
    CGFontRelease(cgFont);
    return font;
}

- (CATextLayer *)customCATextLayer {
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                [NSNumber numberWithFloat:24.f], (NSString *)kCTFontSizeAttribute,
                                [NSNumber numberWithInt:1], (NSString *)kCTLigatureAttributeName,
                                nil];

    CTFontRef font = [self newCustomFontWithName:@"PDMS_Saleem_QuranFont-signed" 
                                          ofType:@"ttf" 
                                      attributes:attributes];

    CATextLayer *normalTextLayer = [[CATextLayer alloc] init];
    normalTextLayer.font = font;
    normalTextLayer.string = NSLocalizedString(@"Sample", nil);
    normalTextLayer.wrapped = YES;
    normalTextLayer.foregroundColor = [[UIColor blackColor] CGColor];
    normalTextLayer.fontSize = 24.f;
    normalTextLayer.alignmentMode = kCAAlignmentCenter;
    normalTextLayer.frame = CGRectMake(0.f, 10.f, 320.f, 32.f);

    CFRelease(font);
    return [normalTextLayer autorelease];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    CATextLayer *normalTextLayer = [self customCATextLayer];
    [self.customView.layer addSublayer:normalTextLayer];
}

Note that I'm using CATextLayer and CTFontRef. There are a few problems with this approach. 1. You'll have to live with the issues in the selected "custom arabic font". 2. You'll have to use the arabic text that uses the extended characters supported by the font.

HTH.

Mustafa
  • 20,504
  • 42
  • 146
  • 209
  • did you find solution for custom arabic fonts? can you take a look at [this](http://stackoverflow.com/questions/20089680/custom-arabic-font-working-in-ios-7-but-not-in-ios-6-or-earlier) – Fahim Parkar Nov 20 '13 at 08:03
  • My solution is presented above. I'm using Core Text and it works. – Mustafa Nov 20 '13 at 10:11
  • You can avoid using Core Text now. You can simpley load the font (set-up in `Info.plist` file), and then use the `NSAttributedString` to display the text in UILabel and/or other iOS provided controls. Thanks. – Mustafa Nov 28 '13 at 08:03
  • @Mustafa i saw some of your other posts and i see that you couldn't render your arabic fonts on UIWebvies.. can I use your solution above with a UIWebview? – abbood Dec 04 '13 at 16:07
  • @abbood Those were old posts. As of iOS 7, the controls like UILabel and UITextView have improved. My solution that uses Core Text can't be used with a UIWebView. Try to follow the simple steps required to use custom font in html/UIWebView, and hopefully it'll work for you. Alternately, simply use UILabel or UITextView with NSAttributedString. – Mustafa Dec 05 '13 at 08:04
  • @Mustafa interesting.. glad you told me this.. but anyways i was already considering alternatives to `UIWebview`.. such as converting the html to text etc.. please update your answer to make it clear that it doesn't address `UIWebview` since your question explicitly mentioned it – abbood Dec 05 '13 at 08:40
  • @Mustafa just for reference i put a [solution](http://stackoverflow.com/a/20423506/766570) that address the `UIWebview` case – abbood Dec 06 '13 at 12:08
  • @Mustafa really nice work. For Displaying Quran, what Script are you using. Could you care to provide a link? – Qamar Suleiman Jun 03 '14 at 19:09
  • I'm using multiple fonts, inlcuding Uthmani Hafs and quran_me. You can easily find these online. – Mustafa Jun 10 '14 at 09:16
4

I first started learning iOS development back in mid 2012, and I've been searching everywhere on the Internet to find a proper solution for custom Persian fonts in iPhone, and could never come up with a proper solution. There was a Core Text library I tried once, and it didn't work always fine, specially that you have to make an additional subview to add your text with the custom font in it. I tried the Arabic Converter a while back and it worked alright, but with the new Xcode it wasn't making a change to the text at all, except in web views, and it only malfunctioned!

So... Anyways, I'm glad Apple is working out problems to support more languages. Now here's the very simple solution that works perfectly fine:

  1. Go to your project's info.plist file,
  2. Right click and select Add row,
  3. Type Fonts provided by application in the new row,
  4. Type in the desired font name as items for this key.

enter image description here

  1. Drag and drop the font file into the project,
  2. Apply it to the text you want:

UITextView *persianText; persianText.text = @"در جستجوی قهرمان نباشید \nبلکه خود قهرمان شوید"; persianText.font = [UIFont fontWithName:@"IranNastaliq" size: 12.0];

Annnd...! Build and run... Tadaaa! It works!

enter image description here

Neeku
  • 3,646
  • 8
  • 33
  • 43
  • 1
    Thank you so much, you saved me a lot of time :) BTW, I started iOS development the same time as you did. Good luck – Hamid Jul 19 '14 at 21:12
3

These classes will do the job :

https://github.com/Accorpa/Arabic-Converter-From-and-To-Arabic-Presentation-Forms-B

Download them, and I'm pretty sure that answers your question because I had the exact same problem before!

An example of the code :

ArabicConverter *converter = [[ArabicConverter alloc] init];
NSString* convertedString = [converter convertArabic:@"منذ دقيقة"];
infoText.font = [UIFont fontWithName:@"YOUARABICFONT" size:16];
infoText.text = convertedString;

Now infoText will display the font correctly :)

Karim
  • 5,298
  • 3
  • 29
  • 35
  • NO, its not giving proper font. – Fahim Parkar Jan 26 '13 at 06:30
  • It might not work with all the fonts in the world, but it did work with all the fonts I tried (except one) – Karim Jan 26 '13 at 10:25
  • Hi @Cookiki can you please tell what fonts worked for you? possible link to the fonts. Thanks in advance – Saraf Talukder Apr 11 '13 at 13:25
  • Hello! The font I used was : bader_algordabia-2.ttf. I was asked to use it in the project I was developing. You can find it here : http://ufonts.com/q96764. I hope this helps! – Karim Apr 16 '13 at 17:22
  • @Cookiki I had used this before in my code and it worked fine. On iOS 7 or Xcode 5 it's not working anymore. The font is the solid annoying default font of the Xcode. I tried many fonts that worked before and they don't work. Any help? – Neeku Nov 17 '13 at 20:01
1

If you're targeting iOS 6, you can use NSAttributedString to achieve this a lot more simply:

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:info.text attributes:@{ NSFontAttributeName : [UIFont fontWithName:@"Scheherazade" size:32], NSLigatureAttributeName: @2}];

cell.textLabel.attributedText = attributedString;

Refer to my answer here for some discussions on other matters commonly relevant to arabic fonts such as line-spacing and ligatures.

Community
  • 1
  • 1
Yazid
  • 970
  • 7
  • 14
  • Would like to see you try this solution with different arabic fonts and share the results. I'll try this when I get the chance. Thanks for sharing. – Mustafa Jun 26 '13 at 04:41
  • This is the easiest method that I've found so far to use embedded arabic fonts, it has made it very simple to interchange fonts and quickly make comparisons. Will be happy to share my results. – Yazid Jun 28 '13 at 11:26
  • I tried `NSAttributedString` for some custom fonts (Persian), and it's not working. No change to the font at all. Have you really had any success with the Arabic fonts? – Neeku Nov 17 '13 at 18:58
  • @Neeku is it possible that you misreferenced the font name? I've successfully used this method (albeit with some bugs) in a published app (https://itunes.apple.com/us/app/iqra!-by-yazid/id672993057?mt=8) – Yazid Nov 21 '13 at 13:11
  • @Yazid No, that wasn't the case, because I tried it many times with many different fonts and it never worked. However I could finally fix it, and I'm putting down the very simple solution here so it can help the others if needed. It's super simple (on newer SDKs of course)! – Neeku Nov 21 '13 at 17:56
  • @Neeku I looked at your answer, I had assumed you had done that before too :) There's a link to a post with those exact steps in another 1 of my related answers references above: http://stackoverflow.com/a/17309179/2358334 – Yazid Nov 22 '13 at 10:45
  • @Yazid Hmm... Your answer in that link is about using the `attributed text`s but I haven't used attributed texts here. It's just a normal string and a normal text view (or label). Actually, trying with attributed ones, I couldn't get a result! However I did notice the links you've provided in that answer and they do have what I have done. My bad! I hadn't seen them before. Thanks anyways. (: – Neeku Nov 22 '13 at 15:08
  • does this work with UIWebViews? i don't think so.. i got a problem where the font works fine with uilabels.. but not so with uiwebview – abbood Dec 04 '13 at 15:32
1

For UIWebview: basically the accepted answer doesn't address the UIWebView case.. So here is a way I addressed this problem.

first: Using hpple, an obj-c HTML parser, I went through the html and basically scrapped the text and appended it to an NSMutableString like so:

// contentText is the HTML text. The format is just text in <p> tags
NSData *contentData = [contentText dataUsingEncoding:NSUTF8StringEncoding];
TFHpple *htmlParser = [TFHpple hppleWithHTMLData:contentData];
NSString *htmlXpathQueryString = @"//p";
NSArray *newsNodes = [htmlParser searchWithXPathQuery:htmlXpathQueryString];
NSMutableArray *newsParagraphs = [@[] mutableCopy];
NSMutableString *newsContent = [@"" mutableCopy];

for (TFHppleElement *element in newsNodes) {
    NSString *paragraphText = [[element firstChild] content];
    [newsParagraphs addObject:paragraphText];
    [newsContent appendFormat:@"%@\n",paragraphText];
}

// explained below (bodyView is a CTContainerView object)
self.bodyView.contentStr = newsContent;
self.bodyView.callback = ^(CGSize size) {
    [self adjustScrollViewSize:size];
};
[self.bodyView buildFrames];

- (void)adjustScrollViewSize:(CGSize)contentSize {
    CGRect overallSize = CGRectUnion(imageView.frame, titleText.frame);
    CGRect bodyViewFr = self.bodyView.frame;
    CGRect bodyViewWrapperFr = CGRectMake(bodyViewFr.origin.x, 
            bodyViewFr.origin.y, contentSize.width, contentSize.height+30);
    overallSize = CGRectUnion(overallSize, bodyViewWrapperFr);
    self.scrollView.contentSize = overallSize.size;
}

Then I used Core Text to render the text into a webview following the steps in this tutorial. Here are the other files:

CTContainerView.h

#import <UIKit/UIKit.h>

typedef void (^CompletionBlock)(CGSize size);
@interface CTContainerView : UIView

@property (nonatomic, strong) NSString *contentStr;
@property (nonatomic, strong) CompletionBlock callback;

- (void)buildFrames;

@end

CTContainerView.m

#import <CoreText/CoreText.h>
#import "CTContainerView.h"
#import "CTView.h"

const float kMargin = 10;

@implementation CTContainerView {
    NSAttributedString* attString;
}

// get the required size for the final view to render
// the complete text of the body.. then pass it on
// to CTContentView
- (void)buildFrames {
    // first build the attributedString with all its properties
    NSString *fontName = @"29LTBukra";  // THE ARABIC FONT NAME!!!!
    CTFontRef fontRef = CTFontCreateWithName((CFStringRef)fontName, 12.0f, NULL);

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setLineSpacing:6];

    NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge id)fontRef, kCTFontAttributeName,
                           paragraphStyle, NSParagraphStyleAttributeName, nil];
    attString = [[NSAttributedString alloc] initWithString:self.contentStr attributes:attrs];

    // get the required final view size given attString
    CGRect selfFr = self.frame;
    CGRect textFr = CGRectInset(selfFr, kMargin, kMargin);
    CGSize requiredSize = [self getRequiredViewSizeInViewWithSize:textFr.size];
    requiredSize.height = requiredSize.height + 100;
    CGRect requiredFrame = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, requiredSize.width, requiredSize.height);

    // construct a CTFrameRef based on the 1. attStr and 2. calculated fr above
    CGMutablePathRef path = CGPathCreateMutable(); //1
    CGPathAddRect(path, NULL, requiredFrame);

    CTFramesetterRef framesetter =
    CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); //3
    CTFrameRef frame =
    CTFramesetterCreateFrame(framesetter,
                             CFRangeMake(0, [attString length]), path, NULL);

    // adjust size of container
    selfFr.size = requiredSize;
    self.frame = selfFr;

    // create an empty CTContentView
    CTView *ctView = [[CTView alloc] initWithFrame: CGRectMake(5, 0, requiredSize.width, requiredSize.height)];
    [ctView setBackgroundColor:[UIColor whiteColor]];
    [ctView setCtFrame:(__bridge id)(frame)];
    [self addSubview:ctView];
    CFRelease(path);

    // call callback
    self.callback(requiredSize);
}

- (CGSize)getRequiredViewSizeInViewWithSize:(CGSize)viewSize {
    CGRect paragraphRect =
    [attString boundingRectWithSize:CGSizeMake(viewSize.width, CGFLOAT_MAX)
                            options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                            context:nil];
    return paragraphRect.size;
}

CTContentView.h

#import <UIKit/UIKit.h>

@interface CTView : UIView
@property (nonatomic, strong) id ctFrame;
@end

CTContentView.m

#import <CoreText/CoreText.h>
#import "CTView.h"

@implementation CTView

@synthesize ctFrame;

-(void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Flip the coordinate system
    CGContextSetTextMatrix(context, CGAffineTransformIdentity);
    CGContextTranslateCTM(context, 0, self.bounds.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CTFrameDraw((CTFrameRef)ctFrame, context);
}

@end
Community
  • 1
  • 1
abbood
  • 23,101
  • 16
  • 132
  • 246
  • Your solution suggest that you're not using `UIWebView` to render arabic text. You're actually using Core Text to render the text. It seems to me that you're just fetching the text from a webpage -- which is perhaps being displayed in a UIWebView? – Mustafa Dec 09 '13 at 13:13
  • no.. my solution is a work around to correctly display arabic text using a custom font to give a final result that looks identical to rendering it in a webview.. iOS has a bug rendering some arabic fonts on UIWebview.. so what I do is that i parse the html content that would normally be displayed on a UIWebview and then render it using core text instead (on a basic UIView).. but the final result is the same for the end user.. which is what matters. – abbood Dec 09 '13 at 13:16
  • @abbood so the end result will be on a UIView? – coder May 30 '18 at 10:19
  • @abood if the text contained URL links or footnotes links, do these still work? If you care to check my detailed question in this link: https://stackoverflow.com/questions/50444788/ebooks-reader-not-capturing-embedded-font-for-epub-file – coder May 30 '18 at 10:32