TFlexCelPdfExport Error trying to embed font 'Calibri' in the document

Hi,
I've made a little app that should shine some more light in what is happening. If you prefer a precompiled exe, you can get it from here:
https://download.tmssoftware.com/flexcel/samples/fontinspector.zip

Or if you want to compile it, the source code is at the end of this post. Please let me know the results: This app will scan all the fonts in the font folder, report if a font is defined twice (what I believe is that you might have a "correct" calibri, but also a "restricted" calibri in the same folder, and FlexCel is using the restricted one). It also will report which files in the c:\windows\fonts folder are "restricted" (so you can't embed them legally).

If, as I suspect, what happens is that there is more than one "calibri" in the font folder, I will fix the FlexCel code to prefer the latest versions of repeated fonts, and also those that aren't restricted. But removing those restricted files on your side should also work. (just open an admin command line and type del filename reported by the app on the files that are restricted and you don't want.

program fontinspector;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  FlexCel.VCLSupport,
  _PdfTrueType.TPdfTrueType,
  _PdfTrueType.TFontDataReader,
  _PdfTrueType.TChunkByteArray,
  _UIClasses.TUIFont,
  _PdfFontFactory.PdfFontFactory,
  _UIClasses.TUIFontStyle,
  __FlexCelTypes,
  Generics.Collections,
  Types,
  IOUtils,
  Classes,
  _PdfTrueType.TTrueTypeInfo,
  _PdfConsts.TPdfFontFolderNotFoundAction,
  _PdfFontFactory.TPsFontList,
  _PdfFontFactory.StringHash
  ;

var
  AllFonts: TDictionary<string, string>;
  DuplicatedFonts: TList<string>;
  RestrictedFonts: TList<string>;

function MakeHash(const name: UTF16String; const style: TUIFontStyleSet): UTF16String;
var
  s: UTF16String;
begin
  s := name;
  if (TUIFontStyle.fsBold in style) then
    s:= s + '-bold-';

  if (TUIFontStyle.fsItalic in style) then
    s:= s + '-italic-';

  Result := s;
end;

procedure LoadFontInternal(const path: UTF16String; const b: TFontDataReader; const OwnsFontData: boolean);
var
  ttfs: TTrueTypeInfoArray;
  ttf: TTrueTypeInfo;
  LocFamilyName: UTF16String;
  FontName, ExistingFontPath: string;
  pdfdef: TPdfTrueType;
begin
  ttfs := TPdfTrueType.GetColection(b, OwnsFontData);
  for ttf in ttfs do
  begin
    for LocFamilyName in ttf.FamilyNames do
    begin

      pdfdef := TPdfTrueType.Create(b, LocFamilyName, OwnsFontData);
      try
        if pdfdef.EmbedForbidden then RestrictedFonts.Add(path);
      finally
        pdfdef.Free;
      end;

      FontName := MakeHash(LocFamilyName, TTrueTypeInfo.GetStyle(ttf.FontFlags));
      if (AllFonts.TryGetValue(FontName, ExistingFontPath)) then
      begin
        DuplicatedFonts.Add('Duplicated Font: ' + FontName + ' is defined in "' + ExistingFontPath + '" and "' + path + '"');
      end
      else
      begin
        AllFonts.Add(FontName, path);
      end;
    end;
  end;
end;


procedure LoadFont(const path: UTF16String; const b: TFontDataReader; const OwnsFontData: boolean);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create(path, FileMode.Open);
  try
    b.Reset(fs);
    LoadFontInternal(path, b, OwnsFontData);
  finally
    FreeObj(fs);
  end;
end;


procedure LoadAllFonts(const FontPath: UTF16String; const FontExtension: UTF16String);
var
  FontPathArray: TArray<UTF16String>;
  fp: UTF16String;
  fi: TStringDynArray;
  FontDataReader: TFontDataReader;
  fontFile: UTF16String;
begin
  FontPathArray := StrSplit(FontPath, ';');
  for fp in FontPathArray do
  begin
    if String_IsNullOrEmpty(fp) then
      continue;

    if fp = TPath.DirectorySeparatorChar then
      continue;

    if not TDirectory.Exists(fp) then
    begin
      WriteLn('Folder not found: ' + fp);
      continue;
    end;

    fi := TDirectory.GetFiles(fp, FontExtension, TSearchOption.soAllDirectories);

    FontDataReader := TFontDataReader.Create;
	try
    for fontFile in fi do
    begin
      case SwitchString(String_ToLowerInvariant(TPath.GetExtension(fontFile))) of
        Int32($2E747463) {'.ttc'}, Int32($2E6F7466) {'.otf'}, Int32($2E747466) {'.ttf'}:
        begin
        end;
        else
        begin
          continue;
        end;
      end;

      try
        LoadFont(fontFile, FontDataReader, false);
      except
        on ex: Exception do
          begin
             //Invalid font. nothing to do, just continue reading the other fonts.
             // What we will do is just ignore it here, and throw an exception when (and if) the user actually tries to use this font.
             WriteLn('Invalid font: ' + fontfile);
          end;
      end;
    end;
    finally
	  FreeObj(FontDataReader);
	end;
  end;
end;

procedure WriteInfo;
var
  f: string;
begin
  if DuplicatedFonts.Count = 0 then WriteLn('There are no duplicated fonts.')
  else
  begin
    WriteLn('**** Duplicated Fonts ****');
    for f in DuplicatedFonts do Writeln(f);
  end;

  WriteLn;

  if RestrictedFonts.Count = 0 then WriteLn('There are no restricted fonts.')
  else
  begin
    WriteLn('**** Restricted Fonts ****');
    for f in RestrictedFonts do Writeln(f);
    WriteLn;
  end;


end;

var
  FontPath: string;

begin
  if ParamCount < 1 then FontPath := 'C:\Windows\Fonts' else FontPath := ParamStr(1);

  AllFonts := TDictionary<string, string>.Create;
  try
    RestrictedFonts := TList<string>.Create;
    try
      DuplicatedFonts := TList<string>.Create;
      try
        LoadAllFonts(FontPath, '*.?t?');
        WriteInfo;
      finally
        DuplicatedFonts.Free;
      end;
    finally
      RestrictedFonts.Free;
    end;
  finally
    AllFonts.Free;
  end;

  ReadLn;
end.

Thats the Result of your Program:
**** Duplicated Fonts ****
Duplicated Font: Calibri-bold- is defined in "C:\Windows\Fonts\calibrib.ttf" and "C:\Windows\Fonts\calibrib_0.ttf"
Duplicated Font: Calibri-italic- is defined in "C:\Windows\Fonts\calibrii.ttf" and "C:\Windows\Fonts\calibrii_0.ttf"
Duplicated Font: Calibri Light-italic- is defined in "C:\Windows\Fonts\calibrili.ttf" and "C:\Windows\Fonts\calibrili_0.ttf"
Duplicated Font: Calibri Light is defined in "C:\Windows\Fonts\calibril.ttf" and "C:\Windows\Fonts\calibril_0.ttf"
Duplicated Font: Calibri-bold--italic- is defined in "C:\Windows\Fonts\calibriz.ttf" and "C:\Windows\Fonts\calibriz_0.ttf"
Duplicated Font: Calibri is defined in "C:\Windows\Fonts\calibri.ttf" and "C:\Windows\Fonts\calibri_0.ttf"
Duplicated Font: Candara is defined in "C:\Windows\Fonts\Candara.ttf" and "C:\Windows\Fonts\Candaral.ttf"
Duplicated Font: Candara-italic- is defined in "C:\Windows\Fonts\Candarai.ttf" and "C:\Windows\Fonts\Candarali.ttf"
Duplicated Font: Roboto-bold- is defined in "C:\Windows\Fonts\Roboto-Black.ttf" and "C:\Windows\Fonts\Roboto-Bold.ttf"
Duplicated Font: Roboto-bold- is defined in "C:\Windows\Fonts\Roboto-Black.ttf" and "C:\Windows\Fonts\Roboto-BoldCondensed.ttf"
Duplicated Font: Roboto-bold--italic- is defined in "C:\Windows\Fonts\Roboto-BlackItalic.ttf" and "C:\Windows\Fonts\Roboto-BoldCondensedItalic.ttf"
Duplicated Font: Roboto-italic- is defined in "C:\Windows\Fonts\Roboto-Italic.ttf" and "C:\Windows\Fonts\Roboto-LightItalic.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Medium.ttf"
Duplicated Font: Roboto Lt is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Medium.ttf"
Duplicated Font: Roboto-bold--italic- is defined in "C:\Windows\Fonts\Roboto-BlackItalic.ttf" and "C:\Windows\Fonts\Roboto-MediumItalic.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Regular.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Thin.ttf"
Duplicated Font: Roboto-italic- is defined in "C:\Windows\Fonts\Roboto-Italic.ttf" and "C:\Windows\Fonts\Roboto-ThinItalic.ttf"

**** Restricted Fonts ****
C:\Windows\Fonts\calibrib_0.ttf
C:\Windows\Fonts\calibrii_0.ttf
C:\Windows\Fonts\calibrili_0.ttf
C:\Windows\Fonts\calibril_0.ttf
C:\Windows\Fonts\calibriz_0.ttf
C:\Windows\Fonts\calibri_0.ttf

I delete the Calibri*_0.ttf files and get these message:

**** Duplicated Fonts ****
Duplicated Font: Candara is defined in "C:\Windows\Fonts\Candara.ttf" and "C:\Windows\Fonts\Candaral.ttf"
Duplicated Font: Candara-italic- is defined in "C:\Windows\Fonts\Candarai.ttf" and "C:\Windows\Fonts\Candarali.ttf"
Duplicated Font: Roboto-bold- is defined in "C:\Windows\Fonts\Roboto-Black.ttf" and "C:\Windows\Fonts\Roboto-Bold.ttf"
Duplicated Font: Roboto-bold- is defined in "C:\Windows\Fonts\Roboto-Black.ttf" and "C:\Windows\Fonts\Roboto-BoldCondensed.ttf"
Duplicated Font: Roboto-bold--italic- is defined in "C:\Windows\Fonts\Roboto-BlackItalic.ttf" and "C:\Windows\Fonts\Roboto-BoldCondensedItalic.ttf"
Duplicated Font: Roboto-italic- is defined in "C:\Windows\Fonts\Roboto-Italic.ttf" and "C:\Windows\Fonts\Roboto-LightItalic.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Medium.ttf"
Duplicated Font: Roboto Lt is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Medium.ttf"
Duplicated Font: Roboto-bold--italic- is defined in "C:\Windows\Fonts\Roboto-BlackItalic.ttf" and "C:\Windows\Fonts\Roboto-MediumItalic.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Regular.ttf"
Duplicated Font: Roboto is defined in "C:\Windows\Fonts\Roboto-Light.ttf" and "C:\Windows\Fonts\Roboto-Thin.ttf"
Duplicated Font: Roboto-italic- is defined in "C:\Windows\Fonts\Roboto-Italic.ttf" and "C:\Windows\Fonts\Roboto-ThinItalic.ttf"

There are no restricted fonts.

And does FlexCel work correctly after deleting the Calibri*_0.ttf files? My guess is that those files were the ones FlexCel was using, and that's why you got the error.

As said, we will fix this now so when a font is repeated, FlexCel favors the "non-restricted" ones. But right now, if you delete the restricted fonts, you shouldn't get errors about embedding restricted fonts.

Hi Adrian
I compiled and ran your code. Did find that there were duplicate Calabri files (Calabri?.ttf and Calabri?_0) with the latter versions marked as restricted. Delete all of the latter, ran my program and successfully generated reports with templates using Calabri!!!! Hip, hip, hooray!

Now if i could only figure out who/what added the restricted versions. I know I had installed some apps around the time this started for me. I may do a file search looking Calabri_0 in contents. I wish I had kept track of changes to my system and that I hadn't been so quick to link the problem to the change to Aptos

Thx!