Arabic text with custom fonts in iOS

前端 未结 5 1944
礼貌的吻别
礼貌的吻别 2020-12-16 06:33

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 tex

相关标签:
5条回答
  • 2020-12-16 06:45

    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.

    0 讨论(0)
  • 2020-12-16 06:47

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

    0 讨论(0)
  • 2020-12-16 06:57

    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

    0 讨论(0)
  • 2020-12-16 06:58

    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.

    0 讨论(0)
  • 2020-12-16 07:12

    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
    
    0 讨论(0)
提交回复
热议问题