Recent

Author Topic: Something's broken in fpTTF : too many fonts causes Stream Read Error  (Read 2335 times)

jipété

  • Full Member
  • ***
  • Posts: 182
Hello,

Consider the following snippet, copied from https://forum.lazarus.freepascal.org/index.php?topic=66967.0, pasted and adapted to my needs, and look at the comments.
Code: Pascal  [Select][+][-]
  1. uses
  2.   fppdf, fpttf;
  3.  
  4. procedure TfrmMain.btnFontlistClick(Sender: TObject);
  5. var  // https://forum.lazarus.freepascal.org/index.php?topic=66967.0
  6.   g: TFPFontCacheList;
  7.   i: Integer;
  8. begin
  9.   //cbfontname.Items.Clear; // orig -- cbfontname is a TComboBox
  10.   lbFamily.Items.Clear; // lbFamily is a TListBox
  11.   //load fonts
  12.   g := TFPFontCacheList.Create;
  13. //g.SearchPath.Add('C:\Windows\Fonts'); orig
  14. //g.SearchPath.Add('d:\Font\');         orig
  15.  
  16. //  g.SearchPath.Add('/usr/share/fonts/truetype/dejavu'); // g.Count = 22 --> light folder, no problem
  17.   g.SearchPath.Add('/usr/share/fonts'); // g.Count = 1116 --> heavy folder, Stream Read Error
  18.  
  19.   g.BuildFontCache;
  20.   showmessage(inttostr(g.Count)); // 1116 or 22
  21.   for i := 0 to g.Count - 1 do
  22. //  if cbfontname.Items.IndexOf(g.Items[i].FamilyName) < 0 then
  23. //    cbfontname.Items.Add(g.Items[i].FamilyName);
  24.     if lbFamily.Items.IndexOf(g.Items[i].FamilyName) < 0 then
  25.       lbFamily.Items.Add(g.Items[i].FamilyName);// Stream Read Error and i = 501
  26.   showmessage(lbFamily.Items.Text); // OK if count < 501
  27.   g.Free;
  28. end;
  29.  
And I don't see where and how to increase the TFPFontCacheList capacity.

Thanks for help...
« Last Edit: July 31, 2024, 07:30:51 am by jipété »

Zvoni

  • Hero Member
  • *****
  • Posts: 2692
This looks like an issue in TTFFileInfo.ParseName, and not an issue that it's 1116 Fonts

It chokes on trying to read the FontName from the FontFile.

maybe corrupted FontFile?

You have an i=501

Have you tried checking manually items 500 and 502?
Or try: rename the file-extension of item 501 in your file-explorer, so the code skips that file
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

paweld

  • Hero Member
  • *****
  • Posts: 1217
This is not a problem with TFPFontCacheList - I checked and it works with more than 2000 font files without any problem.
Probably one or more TTF files are corrupted (or no access to them ?) and the parser can't read them.
Paste the modified code and see how your program behaves
Code: Pascal  [Select][+][-]
  1. uses
  2.   fpttf;
  3.  
  4. procedure TfrmMain.btnFontlistClick(Sender: TObject);
  5. var  // https://forum.lazarus.freepascal.org/index.php?topic=66967.0
  6.   g: TFPFontCacheList;
  7.   i: Integer;
  8. begin
  9.   //cbfontname.Items.Clear; // orig -- cbfontname is a TComboBox
  10.   lbFamily.Items.Clear; // lbFamily is a TListBox
  11.   //load fonts
  12.   g := TFPFontCacheList.Create;
  13.   //g.SearchPath.Add('C:\Windows\Fonts'); orig
  14.   //g.SearchPath.Add('d:\Font\');         orig
  15.  
  16.   //  g.SearchPath.Add('/usr/share/fonts/truetype/dejavu'); // g.Count = 22 --> light folder, no problem
  17.   g.SearchPath.Add('/usr/share/fonts'); // g.Count = 1116 --> heavy folder, Stream Read Error
  18.  
  19.   g.BuildFontCache;
  20.   ShowMessage(IntToStr(g.Count)); // 1116 or 22
  21.   for i := 0 to g.Count - 1 do
  22.   begin
  23.     try
  24.       //  if cbfontname.Items.IndexOf(g.Items[i].FamilyName) < 0 then
  25.       //    cbfontname.Items.Add(g.Items[i].FamilyName);
  26.       if lbFamily.Items.IndexOf(g.Items[i].FamilyName) < 0 then
  27.         lbFamily.Items.Add(g.Items[i].FamilyName);// Stream Read Error and i = 501
  28.     except
  29.       on E: Exception do
  30.         ShowMessage(Format('Error for font index [%d]:' + sLineBreak + '%s', [i, E.Message]);
  31.     end;
  32.   end;
  33.   ShowMessage(lbFamily.Items.Text); // OK if count < 501
  34.   g.Free;
  35. end;        
  36.  
Best regards / Pozdrawiam
paweld

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
The part that is wrong by design is the exception part: you should know beforehand if a font exists or not. No excuse in using exceptions for that, that is simply bad coding.
The other thing that is wrong is not choosing a font family, so there is at least a reasonable alternative.
And yes, you can process well over 2000 fonts without complaints until you meet the counter example.
Those two issues should really have been addressed a long time ago,  and it has been mentioned many times.
That is just not about pdf: it is about handling fonts and font families in general.
« Last Edit: July 09, 2024, 12:46:22 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

dbannon

  • Hero Member
  • *****
  • Posts: 3089
    • tomboy-ng, a rewrite of the classic Tomboy
Its worth noting that the FontCache is substantially improved in FPC- fixes. If you are using FPC322, might be worth trying Fixes.

But do note that if you are using Linux, it opens libfontconfig.so at run time, not libfontconfig.so.1 so your end users need to have the development packages installed !

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

jipété

  • Full Member
  • ***
  • Posts: 182
Well,
first, I've installed the Paweld's code, F9 and Error, see Error501.png.
So I've loaded by path and name all my fonts, below are some lines from 498 to 504, and I've set up the CacheFonts for looking at /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/ only, using the Paweld's code, so 26 fonts have been loaded, no problem :
Code: Pascal  [Select][+][-]
  1. ...
  2. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/amrtypeb.ttf
  3. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/ANDALEMO.TTF  498
  4. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/CodeMorse.ttf 499
  5. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR45W.TTF   500
  6. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR46W.TTF   501
  7. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR65W.TTF   502
  8. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR66W.TTF   503
  9. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/geo703bc.ttf  504
  10. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/LETTERGO.TTF
  11. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/Linedraw.ttf
  12. ...
At the end of some lines are the values found in the memolog when I load all the 1116 fonts

And attached is a try with the fonts between 499 and 504.

HTH,
« Last Edit: July 09, 2024, 02:03:46 pm by jipété »

Zvoni

  • Hero Member
  • *****
  • Posts: 2692
Quote
/usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR46W.TTF   501
Rename dour46w.ttf to dour46w.bak (or whatever. The Fileextension is important) for the code to SKIP that file.
Is it still choking on the next ttf's (dour65w.ttf which would be the "new" Index 501)?
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

jipété

  • Full Member
  • ***
  • Posts: 182
Well, renamed --> no error and the file is not loaded as a file :
Code: Pascal  [Select][+][-]
  1. ...
  2. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/CodeMorse.ttf
  3. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR45W.TTF
  4. <DOUR46W was here>
  5. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR65W.TTF
  6. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/DOUR66W.TTF
  7. /usr/share/fonts/fonts_shared/from_Win2000/Polices/Machine/geo703bc.ttf
  8. ...
Only 1115 files, now.
Anyway, the font is still available for LOWriter or The Gimp, for example... I don't understand...

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
If the font is a resource it does not need to be "installed" under either /user/share/fonts or /usr/local/share/fonts. same goes for Windows.
Fonts are directory entries or resources. So fileexists will work. No exceptions plz. If you need one particular font, simply copy it to the (a) font directory or include the font as a resource.
« Last Edit: July 09, 2024, 03:38:46 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Zvoni

  • Hero Member
  • *****
  • Posts: 2692
If the font is a resource it does not need to be "installed" under either /user/share/fonts or /usr/local/share/fonts. same goes for Windows.
Fonts are directory entries or resources. So fileexists will work. No exceptions plz.
Thaddy, i doubt it has to do with FileExists. (Or was your answer in regards, why the Font is still available to Gimp?)

It's probably a corrupted ttf-file, as TS confirmed in the post above
« Last Edit: July 09, 2024, 03:39:43 pm by Zvoni »
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
That is a possibility, but usually not the most likely. New disk in that case  :P
What I am complaining about is the way exceptions are used here. You understood that very well. You do not use exceptions for that (except if the font file is indeed mutilated and has become unreadable, that is a real exception.)
Such an exception should show up trying to use the font, not enumerating available fonts.
« Last Edit: July 09, 2024, 03:44:39 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Zvoni

  • Hero Member
  • *****
  • Posts: 2692
That is a possibility, but usually not the most likely. New disk in that case  :P

Errr.....you did see, that he did try in Post 7 what i told him (renaming the "offending" ttf-file at Index 501)?
And that TS confirmed his code runs through all 1115 ttf-files with no error?

Meaning: That particular file is different compared to the others (especially since it Chokes in ParseName, which implies FileExists actually returned true).
Conclusion: File corrupted is the most (!!) likely reason
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
Err... I agree with you? But that should still be on use, not on enumeration?
And hard-coded paths?
« Last Edit: July 09, 2024, 03:58:00 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

paweld

  • Hero Member
  • *****
  • Posts: 1217
Quote from: Thaddy
What I am complaining about is the way exceptions are used here. You understood that very well. You do not use exceptions for that (except if the font file is indeed mutilated and has become unreadable, that is a real exception.)
Such an exception should show up trying to use the font, not enumerating available fonts.
And it is for this purpose that I applied try ... except. There is no need to check for the existence of the file because the BuildFontCache routine does that (or more precisely, SearchForFonts).
Best regards / Pozdrawiam
paweld

Thaddy

  • Hero Member
  • *****
  • Posts: 15722
  • Censorship about opinions does not belong here.
No, it simply looks at /etc/fonts/* and examines its files. On windows it is a bit easier. Resource fonts are a bit different. (but I use them a lot) These are never in the font enum.
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018