简体   繁体   English

Delphi - OSX - 从内存流中加载字体

[英]Delphi - OSX - Load font from memory stream

I am trying to load a font from a memory stream on OSX in a Firemonkey (FMX) application with Delphi. 我试图用Delphi在Firemonkey(FMX)应用程序中加载OSX上的内存流中的字体。

Here is the code I tried: 这是我试过的代码:

procedure LoadFontFromStream(SourceStream:TStream);
var cfData:CFDataRef;
    fontBuffer:TBytes;
    fontRef: CGFontRef;
    provider: CGDataProviderRef;
    currentStrRef: CFStringRef;
    currentStr: string;
    streamSize: Int64;
    ctFontReference : CTFontRef;
    ctAscent, ctDescent, ctCapHeight: CGFloat;
begin
  streamSize := SourceStream.Size;
  SetLength(fontBuffer, streamSize);
  SourceStream.Read(fontBuffer[0], streamSize);

  cfData := CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, @fontBuffer[0],
    streamSize, kCFAllocatorNull);
  provider := CGDataProviderCreateWithCFData(cfData);
  CFRelease(cfData);

  fontRef := CGFontCreateWithDataProvider(provider);
  CGDataProviderRelease(provider);

  if fontRef <> nil then
  begin
    ctFontReference := CTFontCreateWithGraphicsFont(fontRef,0.0, nil, nil);
    if ctFontReference <> nil then
    begin
      ctCapHeight := CTFontGetCapHeight(ctFontReference);
      ctAscent := CTFontGetAscent(ctFontReference);
      ctDescent := CTFontGetDescent(ctFontReference);
    end;
    currentStrRef := CTFontCopyFamilyName(ctFontReference);
    currentStr := CFToDelphiString(currentStrRef);
    Log.d('Family name: %s',[currentStr]);
    CFRelease(currentStrRef);
    currentStrRef := CTFontCopyPostscriptName(ctFontReference);
    currentStr := CFToDelphiString(currentStrRef);
    Log.d('Postscript name: %s',[currentStr]);
    CFRelease(currentStrRef);
    currentStrRef := CTFontCopyDisplayName(ctFontReference);
    currentStr := CFToDelphiString(currentStrRef);
    Log.d('Display name: %s',[currentStr]);
    CFRelease(currentStrRef);
  end;
end;

The familyname, postscript name and display name all display correct on the debugger. 姓氏,postscript名称和显示名称都在调试器上显示正确。 However, the font is not loaded/displayed on my form. 但是,我的表单上没有加载/显示字体。 I tried enumerating all font families after running the code and it seems my font (Open Sans) is not present. 我在运行代码后尝试枚举所有字体系列,似乎我的字体(Open Sans)不存在。 Here is how I enumerate the font families: 以下是我枚举字体系列的方法:

procedure ListFonts();
var fontFamilyArray: CFArrayRef;
    i : CFIndex;
    NumFamilies: CFIndex;
    family: CFStringRef;
    familyStr: string;
    foundOpenSans: Boolean;
begin
  foundOpenSans := False;
  fontFamilyArray := CTFontManagerCopyAvailableFontFamilyNames();
  NumFamilies  :=  CFArrayGetCount(fontFamilyArray);
  for i := 0 to NumFamilies-1 do
  begin
    family := CFArrayGetValueAtIndex(fontFamilyArray, i);
    familyStr := CFToDelphiString(family);
    if familyStr.StartsWith('Open') then
    begin
      foundOpenSans := true;
      Log.d('Found %s', [familyStr]);
    end;
  end;

  if not foundOpenSans then
    Log.d('Open Sans not found');

  CFRelease(fontFamilyArray);
end;

I know that loading custom fonts is possible by setting ATSApplicationFontsPath in the info.plist file and placing the files in a folder with my bundle. 我知道通过在info.plist文件中设置ATSApplicationFontsPath并将文件放在包含我的文件夹的文件夹中,可以加载自定义字体。 I tried that and that works. 我试过了,这很有效。 However, I need to load the font from a memory stream. 但是,我需要从内存流中加载字体。

Any ideas why that code doesn't load the font? 任何想法为什么该代码不加载字体? I am running the code to load the font before creating any forms in my app. 我正在运行代码以在我的应用程序中创建任何表单之前加载字体。

I don't see you registering that font with the font manager. 我没有看到你用字体管理器注册该字体。 Have a look at CTFontManagerRegisterGraphicsFont . 看看CTFontManagerRegisterGraphicsFont The documentation explicitly mentions this function for registering fonts that were constructed from memory. 文档明确提到了这个函数,用于注册从内存构造的字体。

The problem was related to the buffer I used. 问题与我使用的缓冲区有关。 Here is how I solved it. 这是我如何解决它。

procedure LoadFontFromStream(SourceStream:TStream);
var cfData:CFDataRef;
    fontBuffer:TBytes;
    fontRef: CGFontRef;
    provider: CGDataProviderRef;
    streamSize: Int64;
    theError: CFErrorRef;
    errorDescription : CFStringRef;
    errorDescriptionString : string;
    registerFontValue: Integer;
begin
  streamSize := SourceStream.Size;
  SetLength(fontBuffer, streamSize);
  SourceStream.Read(fontBuffer[0], streamSize);
  cfData := CFDataCreate(kCFAllocatorDefault, @fontBuffer[0],streamSize);
  provider := CGDataProviderCreateWithCFData(cfData);
  CFRelease(cfData);
  fontRef := CGFontCreateWithDataProvider(provider);
  CGDataProviderRelease(provider);
  if fontRef <> nil then
  begin
    theError := nil;
    registerFontValue :=CTFontManagerRegisterGraphicsFont(fontRef, @theError);
    if theError <> nil then
    begin
      errorDescription := CFErrorCopyDescription(theError);
      errorDescriptionString := CFToDelphiString(errorDescription);
      Log.d('Error loading font: %s', [errorDescriptionString]);
      CFRelease(errorDescription);
    end;
  end;
end;

However, this only works on OSX 10.8 and later as CTFontManagerRegisterGraphicsFont is not availabile on OSX 10.7. 但是,这仅适用于OSX 10.8及更高版本,因为CTFontManagerRegisterGraphicsFont在OSX 10.7上不可用。 Any idea on what method is available on OSX 10.7? 想知道OSX 10.7上有哪些方法可用?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM