iOS 中带有自定义字体的阿拉伯文本

发布于 2024-12-04 15:18:36 字数 949 浏览 1 评论 0原文

我正在开发一个需要使用自定义阿拉伯字体显示阿拉伯文本的应用程序。问题是我没有运气使用自定义阿拉伯字体显示阿拉伯文本。我尝试在 UILabel、UITextField、UITextView、UIWebView、FontLabel(Zynga 提供)中显示文本,并使用 CoreText。

您可以在此处找到示例项目:

使用 UILabel、UITextField、UITextView 和 CoreText 的示例应用程序

使用 UIWebView (HTML) 的示例应用程序

使用 UIWebView (HTML) 的示例应用程序:您必须安装 示例项目中的字体。然后您可以比较结果并查看 通过在模拟器(或 iPad)中运行应用程序来解决问题,以及 在浏览器 (Safari) 中打开 Sample.html 文件。

我已经在 Apple 开发者论坛上发布了一些详细信息,但我总是发现 stackoverflow 比 Apple 官方开发者论坛活跃得多。这是该帖子的链接:

在 iOS 中使用自定义阿拉伯字体

我做错了什么?

注意:字体已正确加载到系统中,并且我可以成功地将自定义字体应用于常规(英文)文本。

ps stackoverflow 上有几篇文章讨论了这个主题,但没有一个有太大帮助,所以我发布了一个新问题。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

以往的大感动 2024-12-11 15:18:36

更新:

从 iOS 7 开始,您实际上不需要使用 Core Text 来渲染自定义阿拉伯字体。您可以将 UILabel 和/或 UITextViewNSAttributedString 一起使用。结果与使用 Core-Text 得到的结果相同。但是,根据您的要求,使用 Core Text 仍然是更好的选择。

更新:

我已将此作为错误报告给 Apple,但我不确定他们何时会添加对阿拉伯字体的支持。目前,还没有简单的方法可以做到这一点。我最终使用了默认的系统字体,这不是很好。

原始消息

我确实设法构建了一个使用自定义阿拉伯字体的古兰经应用程序。我使用已知的阿拉伯字体和 Core Text 框架来获得所需的结果。你可以通过检查应用程序古兰经来看到我最终得到的结果iPad 版 Presenter,可从 App Store 获取。

这里有一些示例代码可以帮助您:

- (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];
}

请注意,我使用的是 CATextLayerCTFontRef。这种方法存在一些问题。
1.您将不得不忍受所选“自定义阿拉伯字体”中的问题。
2. 您必须使用使用字体支持的扩展字符的阿拉伯文本。

HTH。

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.

陈独秀 2024-12-11 15:18:36

我第一次学习 iOS 开发是在 2012 年中,当时我一直在互联网上到处寻找 iPhone 中自定义波斯字体的合适解决方案,但始终找不到合适的解决方案。我尝试过一个 Core Text 库,但它并不总是正常工作,特别是您必须创建一个额外的 subview 来添加带有自定义字体的文本在其中。我不久前尝试过阿拉伯语转换器,它工作得很好,但是使用新的 Xcode,除了 Web 视图之外,它根本没有对文本进行任何更改,而且它只是出现了故障!

所以……无论如何,我很高兴苹果正在解决支持更多语言的问题。现在,这是一个非常简单的解决方案,效果非常好:

  1. 转到项目的 info.plist 文件,
  2. 右键单击并选择添加行
  3. 输入应用程序提供的字体< /code> 在新行中,
  4. 键入所需的字体名称作为该键的项目。

在此处输入图像描述

  1. 将字体文件拖放到项目中,
  2. 将其应用到您想要的文本:

UITextView *波斯语文本;
persianText.text = @"德瑞·巴德·德·德·德·德·德·德·德·德·德·德·德·德·德·德·德·德·德·德";
persianText.font = [UIFont fontWithName:@"IranNastaliq" size: 12.0];

安...!构建并运行...Tadaaa!有用!

在此处输入图像描述

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

幻想少年梦 2024-12-11 15:18:36

这些课程将完成这项工作:

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

下载它们,我很确定这回答了你的问题,因为我有完全相同的之前的问题!

代码示例:

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

现在 infoText 将正确显示字体:)

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

悲念泪 2024-12-11 15:18:36

如果您的目标是 iOS 6,则可以使用 NSAttributedString 更简单地实现此目的:

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

cell.textLabel.attributedText = attributedString;

请参阅我的答案 此处有关与阿拉伯字体通常相关的其他问题(例如行距和连字)的一些讨论。

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.

蓦然回首 2024-12-11 15:18:36

对于UIWebview:基本上接受的答案没有解决UIWebView 案例.. 这是我解决这个问题的方法。

首先:使用hpple,一个obj-c HTML解析器,我经历了html 并基本上废弃了文本并将其附加到 NSMutableString 中,如下所示:

// 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;
}

然后,我按照 本教程。以下是其他文件:

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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文