的iOS CoreText通过CTFontManagerRegisterGraphicsFont

问题描述:

我注册字体得到登记的字体列表中动态地通过如下:的iOS CoreText通过CTFontManagerRegisterGraphicsFont

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ 

    if ([url isFileURL]) 
    { 
     // Handle file being passed in 
     NSLog(@"handleOpenURL: %@",url.absoluteString); 


     NSData *inData = [NSData dataWithContentsOfURL:url]; 
     CFErrorRef error; 
     CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData); 
     CGFontRef fontRef = CGFontCreateWithDataProvider(provider); 

     UIFont *font; 
     if (!CTFontManagerRegisterGraphicsFont(fontRef, &error)) { 
      CFStringRef errorDescription = CFErrorCopyDescription(error); 
      NSLog(@"Failed to load font: %@", error); 
      CFRelease(errorDescription); 
     } else { 
      CFStringRef fontNameRef = CGFontCopyPostScriptName(fontRef); 
      NSLog(@"fontNameRef: %@",fontNameRef); 
      font = [UIFont fontWithName:(__bridge NSString *)fontNameRef size:80]; 
      [self.arrayOfFonts addObject:(__bridge NSString *)fontNameRef]; 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshFont" object:nil]; 
      CFRelease(fontNameRef); 
     } 
     CFRelease(fontRef); 
     CFRelease(provider); 
     return YES; 
    } 
    else 
    { 
     return NO; 
    } 
} 

它工作正常第一次。看起来,如果我关闭应用程序并尝试再次注册相同的字体,那么它会给我(预期的)错误"Failed to load font: Error Domain=com.apple.CoreText.CTFontManagerErrorDomain Code=105 "Could not register the CGFont '<CGFont (0x1c00f5980): NeuropolXRg-Regular>'" UserInfo={NSDescription=Could not register the CGFont '<CGFont (0x1c00f5980): NeuropolXRg-Regular>', CTFailedCGFont=<CGFont (0x1c00f5980): NeuropolXRg-Regular>}"

这似乎是因为字体已被注册。 CTFontManagerRegisterGraphicsFont的文档声明:

“使用字体管理器注册指定的图形字体注册字体可通过字体描述符匹配发现尝试注册已注册的字体或包含相同的PostScript名称的字体已经注册的字体将失败。“

“通过字体描述符匹配”到底该怎么办?

如何获取已通过CTFontManagerRegisterGraphicsFont方法注册的所有字体列表,以便我可以在注册之前取消注册它们?

编辑:

我已经使用CTFontManagerCopyAvailablePostScriptNamesCTFontManagerCopyAvailableFontFamilyNames方法,但都只有打印出来iOS上已经提供的字体的名称尝试。不是那些我通过CTFontManagerRegisterGraphicsFont

注意注册:我不是问已经可以在iOS上可以通过遍历[UIFont familyNames]被列出的字体。

+0

有人可以帮我吗? –

+0

“关闭应用程序”是什么意思? –

+0

另外,你有没有尝试过['CTFontManagerCopyAvailablePostScriptNames'](https://developer.apple.com/documentation/coretext/1499516-ctfontmanagercopyavailablepostsc)? –

我记录的一票与苹果DTS(开发者技术支持),他们说:

“你需要跟踪自己使用CTFontManagerRegisterGraphicsFont注册的字体,CTFontManagerRegisterGraphicsFont返回的错误代码kCTFontManagerErrorAlreadyRegistered会告诉你如果你已经注册了一种字体。使用字体描述符匹配来发现您的字体是否安装可能不是一个好方法,因为系统可能会选择对丢失的字体进行字体替换。使用CTFontManagerRegisterGraphicsFont安装字体只是使它可用于您的应用程序的使用。它不是用于发现已安装字体的查询服务。如果这还不足以满足您的偏好,那么我认为您可以考虑提交功能请求,询问您希望收到的功能。“

所以基本上,我们需要跟踪这些字体我们注册自己的

解决方案/变通最后我用:。

目前我的应用程序允许用户使用Action Sheet's“复制到MYAPP”按钮上的字体文件添加字体同样的解决方案也适用于我从我的服务器下载的字体文件。

为了在行动表上列出我的应用程序的.ttf.otf文件,在我的应用程序的Info.plist,我添加了一个新的文档类型:

<key>CFBundleDocumentTypes</key> 
    <array> 
     <dict> 
      <key>CFBundleTypeIconFiles</key> 
      <array/> 
      <key>CFBundleTypeName</key> 
      <string>Font</string> 
      <key>LSItemContentTypes</key> 
      <array> 
       <string>public.opentype-font</string> 
       <string>public.truetype-ttf-font</string> 
      </array> 
     </dict> 
    </array> 

这让我的应用程序,以显示任何字体文件上的action sheet。所以用户可以将字体文件放在Dropbox,谷歌驱动器或任何其他文件共享应用程序。然后他们可以从那里导入字体到我的应用程序。导入后,我需要将字体文件从临时文件夹中移动到我的应用程序的Documentsfonts目录中。 fonts目录保留所有的自定义字体。之后,我注册这个自定义字体并将名称添加到self.arrayOfFonts阵列。这是包含我所有字体列表的数组。

此外,它似乎CTFontManagerRegisterGraphicsFont只是会议。所以当应用程序从应用程序切换器关闭并重新启动时,该字体不再被注册。因此,在每次启动后,我会浏览我的documents/fonts文件夹并重新注册所有字体并将其名称添加到self.arrayOfFonts阵列中。

休息的我的应用程序代码得到这个工作:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{ 

    if ([url isFileURL]) 
    { 
     // Handle file being passed in 
     NSLog(@"handleOpenURL: %@, extension: %@",url.absoluteString,url.pathExtension); 
     [self moveFontFrom:url]; 
     return YES; 
    } 
    else 
    { 
     return NO; 
    } 
} 

-(void)moveFontFrom:(NSURL*)fromurl{ 
    NSString *stringPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingPathComponent:@"fonts"]; 
    // New Folder is your folder name 
    NSError *error1 = nil; 
    if (![[NSFileManager defaultManager] fileExistsAtPath:stringPath]){ 
     [[NSFileManager defaultManager] createDirectoryAtPath:stringPath withIntermediateDirectories:NO attributes:nil error:&error1]; 
    } 
    NSLog(@"error1: %@", error1.debugDescription); 
    NSURL *tourl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",stringPath,[[fromurl absoluteString] lastPathComponent]] isDirectory:NO]; 

    NSLog(@"Trying to move from:\n\n%@\n\nto:\n\n%@\n\n", fromurl.absoluteString,tourl.absoluteString); 

    NSError* error2; 
    if ([[NSFileManager defaultManager] fileExistsAtPath:tourl.path]){ 
     [[NSFileManager defaultManager] removeItemAtPath:tourl.path error:&error2]; 
     NSLog(@"Deleting old existing file at %@ error2: %@", tourl.path,error2.debugDescription); 
    } 


    NSError* error3; 
    [[NSFileManager defaultManager] moveItemAtURL:fromurl toURL:tourl error:&error3]; 
    NSLog(@"error3: %@", error3.debugDescription); 

    if (!error3) { 
     NSString *fontName = [self registerFont:tourl checkIfNotify:YES]; 
     if (fontName) { 
      if (![self.arrayOfFonts containsObject:fontName]) { 
       [self.arrayOfFonts addObject:fontName]; 
       [self.arrayOfFonts sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; 
       [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshFont" object:nil userInfo:@{@"font":fontName}]; 
      } 
     } 
    } 
} 

-(void)startupLoadFontsInDocuments{ 

    self.arrayOfFonts = [NSMutableArray new]; 
    NSString *location = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0] stringByAppendingPathComponent:@"fonts"]; 
    NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:location error:NULL]; 
    for (NSInteger count = 0; count < [directoryContent count]; count++) 
    { 
     NSLog(@"File %ld: %@/%@", (count + 1), location,[directoryContent objectAtIndex:count]); 
     NSString *fontName = [self registerFont:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@",location,[directoryContent objectAtIndex:count]] isDirectory:NO] checkIfNotify:NO]; 
     if (fontName) { 
      if (![self.arrayOfFonts containsObject:fontName]) { 
       [self.arrayOfFonts addObject:fontName]; 
      } 
     } 
    } 
    [self.arrayOfFonts sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; 
} 

-(NSString*)registerFont:(NSURL *)url checkIfNotify:(BOOL)checkIfNotify{ 
    NSData *inData = [NSData dataWithContentsOfURL:url]; 
    CFErrorRef registererror; 
    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData); 
    CGFontRef fontRef = CGFontCreateWithDataProvider(provider); 
    NSString *fontName = (__bridge NSString *)CGFontCopyPostScriptName(fontRef); 
    BOOL registerFontStatus = CTFontManagerRegisterGraphicsFont(fontRef, &registererror); 
    if (!registerFontStatus) { 
     CFStringRef errorDescription = CFErrorCopyDescription(registererror); 
     NSError *registererr = (__bridge NSError*)registererror; 
     if ([registererr code]==kCTFontManagerErrorAlreadyRegistered) { 
      NSLog(@"Font is already registered!"); 
     } 
     NSLog(@"Failed to load font: %@", registererror); 
     CFRelease(errorDescription); 

     /*CFErrorRef unregistererror; 
    BOOL unregisterFont = CTFontManagerUnregisterGraphicsFont(fontRef, &unregistererror); 
    NSLog(@"Font unregister status: %d",unregisterFont); 
    CFStringRef unregistererrorDescription = CFErrorCopyDescription(unregistererror); 
    NSError *unregistererr = (__bridge NSError*)unregistererror; 
    NSInteger code = [unregistererr code]; 

    NSLog(@"Failed to unregister font: %@", unregistererr); 
    CFRelease(unregistererrorDescription);*/ 

     if (checkIfNotify) { 
      UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Already added" message:@"That font is already added to the app. Please select it from the fonts list." preferredStyle:UIAlertControllerStyleAlert]; 
      [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 

      }]]; 
      [[self.window rootViewController] presentViewController:alert animated:YES completion:nil]; 
     } 
    } else { 
     CFStringRef fontNameRef = CGFontCopyPostScriptName(fontRef); 
     fontName = (__bridge NSString*)fontNameRef; 
     CFRelease(fontNameRef); 

     NSLog(@"fontName: %@",fontName); 
    } 
    CFRelease(fontRef); 
    CFRelease(provider); 
    return fontName; 
} 

注:正如你将发现,我已经注释掉CTFontManagerUnregisterGraphicsFont。用于取消注册字体的CTFontManagerUnregisterGraphicsFont似乎不适用于我,因为它提供了一个错误消息,说明字体正在使用中,因此无法取消注册。所以当我需要删除字体时,我只需将它从self.arrayOfFonts阵列和我的documents/fonts文件夹中删除。

你应该使用什么是这样的:

- (void)getInstalledFonts { 
    NSDictionary *descriptorOptions = @{(id)kCTFontDownloadableAttribute : @YES}; 
    CTFontDescriptorRef descriptor = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)descriptorOptions); 
    CFArrayRef fontDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(descriptor, NULL); 
    [self showExistingFonts:(NSArray *)CFBridgingRelease(fontDescriptors)]; 
    CFRelease(descriptor); 
} 

- (void)showExistingFonts:(NSArray *)fontList { 
    NSMutableDictionary *fontFamilies = [NSMutableDictionary new]; 
    for(UIFontDescriptor *descriptor in fontList) { 
     NSString *fontFamilyName = [descriptor objectForKey:UIFontDescriptorFamilyAttribute]; 
     NSMutableArray *fontDescriptors = [fontFamilies objectForKey:fontFamilyName]; 
     if(!fontDescriptors) { 
      fontDescriptors = [NSMutableArray new]; 
      [fontFamilies setObject:fontDescriptors forKey:fontFamilyName]; 
     } 

     [fontDescriptors addObject:descriptor]; 
    } 

} 

来自 https://www.shinobicontrols.com/blog/ios7-day-by-day-day-22-downloadable-fonts

+0

我试过这个,做了'fontFamilyName'的'NSLog'。我测试了3种自定义字体,但没有列出它们。它打印出我可以通过'[UIFont familyNames]'获得的所有名称,但它没有打印我通过'CTFontManagerRegisterGraphicsFont'注册的自定义字体。 –

+0

尝试使用其他descriptorOptions。有很多可用的https://developer.apple.com/documentation/coretext/core_text_constants – Lefteris

+0

我试过'kCTFontDownloadedAttribute','kCTFontDownloadableAttribute'并且没有运气。我联系了Apple DTS,他们说我需要自己跟踪我的字体,并且“使用字体描述符匹配来发现您的字体是否安装可能不是一个好方法,因为系统可能会选择执行缺少字体替换字体“。 我最终使用了我在此共享的解决方案: https://*.com/a/45284412/1634905 –