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

时间:2015-10-10 23:42:20

标签: macos delphi fonts core-text

我正在尝试使用Delphi在Firemonkey(FMX)应用程序中的OSX上加载内存流中的字体。

这是我尝试过的代码:

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;

在调试器上显示的姓氏,postscript名称和显示名称都是正确的。但是,我的表单上没有加载/显示字体。我在运行代码后尝试枚举所有字体系列,似乎我的字体(Open Sans)不存在。以下是我枚举字体系列的方法:

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;

我知道通过在info.plist文件中设置ATSApplicationFontsPath并将文件放在包含我的文件夹的文件夹中,可以加载自定义字体。我试过了,这很有效。但是,我需要从内存流中加载字体。

为什么代码不加载字体的任何想法?我正在运行代码以在我的应用程序中创建任何表单之前加载字体。

2 个答案:

答案 0 :(得分:0)

我没有看到你用字体管理器注册该字体。看看CTFontManagerRegisterGraphicsFont。 文档明确提到了这个函数,用于注册从内存构造的字体。

答案 1 :(得分:0)

问题与我使用的缓冲区有关。以下是我解决它的方法。

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;

但是,这仅适用于OSX 10.8及更高版本,因为CTFontManagerRegisterGraphicsFont在OSX 10.7上不可用。有关OSX 10.7上可用的方法的任何想法吗?