View Issue Details

IDProjectCategoryView StatusLast Update
0035251FPCFCLpublic2019-12-05 16:08
ReporterLacaKAssigned ToMichael Van Canneyt 
PrioritynormalSeverityminorReproducibilityalways
Status acknowledgedResolutionreopened 
PlatformOSWindowsOS Version
Product Version3.0.4Product Build 
Target VersionFixed in Version3.3.1 
Summary0035251: fcl-pdf: Writing text in "Courier New" TTF font generates wrong PDF document
DescriptionTry run attached program an look on outputted PDF file.
There are 4 lines in :
- Courier New, Arial, Verdana and Consolas fonts
- 1st line in Courier New font is wrong, other three lines in another fonts are okay.
Additional InformationAttached test program, generated PDF file and screen shot of content of PDF file
Tagsfcl-pdf, fpPDF
Fixed in Revision41800
FPCOldBugId0
FPCTarget-
Attached Files
  • test_fpPDF.lpr (1,575 bytes)
  • test.pdf (66,822 bytes)
  • CourierNew.PNG (6,538 bytes)
    CourierNew.PNG (6,538 bytes)
  • test-noembed.pdf (4,958 bytes)
  • 0001-fppdf-fixes-glyph-width-range-check-error-for-monosp.patch (1,824 bytes)
    From 09af9dc3fb6ad4d810ea7226fadc2f80b21f9eca Mon Sep 17 00:00:00 2001
    From: Graeme Geldenhuys <graemeg@gmail.com>
    Date: Thu, 21 Mar 2019 16:14:09 +0000
    Subject: [PATCH 1/2] fppdf: fixes glyph width range check error for monospaced
     fonts.
    
    ---
     packages/fcl-pdf/src/fppdf.pp | 20 ++++++++++++++++++--
     1 file changed, 18 insertions(+), 2 deletions(-)
    
    diff --git a/packages/fcl-pdf/src/fppdf.pp b/packages/fcl-pdf/src/fppdf.pp
    index 56be0c008a..125322a61f 100644
    --- a/packages/fcl-pdf/src/fppdf.pp
    +++ b/packages/fcl-pdf/src/fppdf.pp
    @@ -1686,14 +1686,30 @@ procedure TPDFTrueTypeCharWidths.Write(const AStream: TStream);
       s: string;
       lst: TTextMappingList;
       lFont: TTFFileInfo;
    +  lWidthIndex: integer;
     begin
       s := '';
       lst := Document.Fonts[EmbeddedFontNum].TextMapping;
       lst.Sort;
       lFont := Document.Fonts[EmbeddedFontNum].FTrueTypeFile;
    -  // use decimal values for the output
    +
    +  {$IFDEF gdebug}
    +  System.WriteLn('****** isFixedPitch = ', BoolToStr(lFont.PostScript.isFixedPitch > 0, True));
    +  System.WriteLn('****** Head.UnitsPerEm := ', lFont.Head.UnitsPerEm );
    +  System.WriteLn('****** HHead.numberOfHMetrics := ', lFont.HHead.numberOfHMetrics );
    +  {$ENDIF}
    +
    +  { NOTE: Monospaced fonts may not have a width for every glyph
    +          the last one is for subsequent glyphs.  }
       for i := 0 to lst.Count-1 do
    -    s :=  s + Format(' %d [%d]', [ lst[i].GlyphID, TTTFFriendClass(lFont).ToNatural(lFont.Widths[lst[i].GlyphID].AdvanceWidth)]);
    +  begin
    +    if lst[i].GlyphID < lFont.HHead.numberOfHMetrics then
    +      lWidthIndex := lst[i].GlyphID
    +    else
    +      lWidthIndex := lFont.HHead.numberOfHMetrics-1;
    +    s :=  s + Format(' %d [%d]', [lst[i].GlyphID, TTTFFriendClass(lFont).ToNatural(lFont.Widths[lWidthIndex].AdvanceWidth)])
    +  end;
    +
       WriteString(s, AStream);
     end;
     
    -- 
    2.17.1
    
    
  • 0002-fcl-pdf-ttfdump-fixes-glyph-width-range-check-error-.patch (2,331 bytes)
    From 5cd9586f418467806f8336c679623305ac4acd4d Mon Sep 17 00:00:00 2001
    From: Graeme Geldenhuys <graemeg@gmail.com>
    Date: Thu, 21 Mar 2019 16:14:55 +0000
    Subject: [PATCH 2/2] fcl-pdf ttfdump: fixes glyph width range check error for
     monospaced fonts.
    
    ---
     packages/fcl-pdf/utils/ttfdump.lpr | 22 +++++++++++++++++++---
     1 file changed, 19 insertions(+), 3 deletions(-)
    
    diff --git a/packages/fcl-pdf/utils/ttfdump.lpr b/packages/fcl-pdf/utils/ttfdump.lpr
    index 9e564b9773..ce2f8df27b 100644
    --- a/packages/fcl-pdf/utils/ttfdump.lpr
    +++ b/packages/fcl-pdf/utils/ttfdump.lpr
    @@ -37,6 +37,21 @@   TFriendClass = class(TTFFileInfo)
     { TMyApplication }
     
     procedure TMyApplication.DumpGlyphIndex;
    +
    +  procedure PrintGlyphWidth(const aIndex: UInt32);
    +  var
    +    lWidthIndex: integer;
    +  begin
    +    { NOTE: Monospaced fonts may not have a width for every glyph
    +            the last one is for subsequent glyphs.  }
    +    if aIndex < FFontFile.HHead.numberOfHMetrics then
    +      lWidthIndex := FFontFile.Chars[aIndex]
    +    else
    +      lWidthIndex := FFontFile.HHead.numberOfHMetrics-1;
    +
    +    Writeln(Format('  %3d = %d', [FFontFile.Chars[aIndex], TFriendClass(FFontFile).ToNatural(FFontFile.Widths[lWidthIndex].AdvanceWidth)]));
    +  end;
    +
     begin
       Writeln('FHHead.numberOfHMetrics = ', FFontFile.HHead.numberOfHMetrics);
       Writeln('Length(Chars[]) = ', Length(FFontFile.Chars));
    @@ -47,9 +62,9 @@ procedure TMyApplication.DumpGlyphIndex;
       Writeln('  U+0048 (H) = ', Format('%d  (%0:4.4x)', [FFontFile.Chars[$0048]]));
       writeln;
       Writeln('Glyph widths:');
    -  Writeln('  3 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0020]].AdvanceWidth));
    -  Writeln('  4 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0021]].AdvanceWidth));
    -  Writeln('  H = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0048]].AdvanceWidth));
    +  PrintGlyphWidth($0020);
    +  PrintGlyphWidth($0021);
    +  PrintGlyphWidth($0048);
     end;
     
     function TMyApplication.GetGlyphIndices(const AText: UnicodeString): TTextMappingList;
    @@ -121,6 +136,7 @@ procedure TMyApplication.DoRun;
       end;
     
       FFontFile.LoadFromFile(self.GetOptionValue('f'));
    +  Writeln('Postscript.IsFixedPitch = ', BoolToStr(FFontFile.PostScript.isFixedPitch > 0, True));
       DumpGlyphIndex;
     
       // test #1
    -- 
    2.17.1
    
    
  • test-embed2.pdf (39,109 bytes)
  • test-noembed2.pdf (5,040 bytes)

Activities

LacaK

2019-03-20 09:34

developer  

test_fpPDF.lpr (1,575 bytes)

LacaK

2019-03-20 09:35

developer  

test.pdf (66,822 bytes)

LacaK

2019-03-20 09:36

developer  

CourierNew.PNG (6,538 bytes)
CourierNew.PNG (6,538 bytes)

LacaK

2019-03-21 09:38

developer  

test-noembed.pdf (4,958 bytes)

LacaK

2019-03-21 09:40

developer   ~0114956

Last edited: 2019-03-21 11:04

View 3 revisions

I have attached "test-noembed.pdf" (generated using poNoEmbeddedFonts option) where is NO-embedded font inside file.

Look at Font definition and Font descriptor especialy for /W and /MissingWidth.
IMO extracted values are too high to be right ...
(so probably there is specific problem with "Courier New" font parsing)

Graeme Geldenhuys

2019-03-21 17:18

reporter  

0001-fppdf-fixes-glyph-width-range-check-error-for-monosp.patch (1,824 bytes)
From 09af9dc3fb6ad4d810ea7226fadc2f80b21f9eca Mon Sep 17 00:00:00 2001
From: Graeme Geldenhuys <graemeg@gmail.com>
Date: Thu, 21 Mar 2019 16:14:09 +0000
Subject: [PATCH 1/2] fppdf: fixes glyph width range check error for monospaced
 fonts.

---
 packages/fcl-pdf/src/fppdf.pp | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/packages/fcl-pdf/src/fppdf.pp b/packages/fcl-pdf/src/fppdf.pp
index 56be0c008a..125322a61f 100644
--- a/packages/fcl-pdf/src/fppdf.pp
+++ b/packages/fcl-pdf/src/fppdf.pp
@@ -1686,14 +1686,30 @@ procedure TPDFTrueTypeCharWidths.Write(const AStream: TStream);
   s: string;
   lst: TTextMappingList;
   lFont: TTFFileInfo;
+  lWidthIndex: integer;
 begin
   s := '';
   lst := Document.Fonts[EmbeddedFontNum].TextMapping;
   lst.Sort;
   lFont := Document.Fonts[EmbeddedFontNum].FTrueTypeFile;
-  // use decimal values for the output
+
+  {$IFDEF gdebug}
+  System.WriteLn('****** isFixedPitch = ', BoolToStr(lFont.PostScript.isFixedPitch > 0, True));
+  System.WriteLn('****** Head.UnitsPerEm := ', lFont.Head.UnitsPerEm );
+  System.WriteLn('****** HHead.numberOfHMetrics := ', lFont.HHead.numberOfHMetrics );
+  {$ENDIF}
+
+  { NOTE: Monospaced fonts may not have a width for every glyph
+          the last one is for subsequent glyphs.  }
   for i := 0 to lst.Count-1 do
-    s :=  s + Format(' %d [%d]', [ lst[i].GlyphID, TTTFFriendClass(lFont).ToNatural(lFont.Widths[lst[i].GlyphID].AdvanceWidth)]);
+  begin
+    if lst[i].GlyphID < lFont.HHead.numberOfHMetrics then
+      lWidthIndex := lst[i].GlyphID
+    else
+      lWidthIndex := lFont.HHead.numberOfHMetrics-1;
+    s :=  s + Format(' %d [%d]', [lst[i].GlyphID, TTTFFriendClass(lFont).ToNatural(lFont.Widths[lWidthIndex].AdvanceWidth)])
+  end;
+
   WriteString(s, AStream);
 end;
 
-- 
2.17.1

Graeme Geldenhuys

2019-03-21 17:19

reporter  

0002-fcl-pdf-ttfdump-fixes-glyph-width-range-check-error-.patch (2,331 bytes)
From 5cd9586f418467806f8336c679623305ac4acd4d Mon Sep 17 00:00:00 2001
From: Graeme Geldenhuys <graemeg@gmail.com>
Date: Thu, 21 Mar 2019 16:14:55 +0000
Subject: [PATCH 2/2] fcl-pdf ttfdump: fixes glyph width range check error for
 monospaced fonts.

---
 packages/fcl-pdf/utils/ttfdump.lpr | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/packages/fcl-pdf/utils/ttfdump.lpr b/packages/fcl-pdf/utils/ttfdump.lpr
index 9e564b9773..ce2f8df27b 100644
--- a/packages/fcl-pdf/utils/ttfdump.lpr
+++ b/packages/fcl-pdf/utils/ttfdump.lpr
@@ -37,6 +37,21 @@   TFriendClass = class(TTFFileInfo)
 { TMyApplication }
 
 procedure TMyApplication.DumpGlyphIndex;
+
+  procedure PrintGlyphWidth(const aIndex: UInt32);
+  var
+    lWidthIndex: integer;
+  begin
+    { NOTE: Monospaced fonts may not have a width for every glyph
+            the last one is for subsequent glyphs.  }
+    if aIndex < FFontFile.HHead.numberOfHMetrics then
+      lWidthIndex := FFontFile.Chars[aIndex]
+    else
+      lWidthIndex := FFontFile.HHead.numberOfHMetrics-1;
+
+    Writeln(Format('  %3d = %d', [FFontFile.Chars[aIndex], TFriendClass(FFontFile).ToNatural(FFontFile.Widths[lWidthIndex].AdvanceWidth)]));
+  end;
+
 begin
   Writeln('FHHead.numberOfHMetrics = ', FFontFile.HHead.numberOfHMetrics);
   Writeln('Length(Chars[]) = ', Length(FFontFile.Chars));
@@ -47,9 +62,9 @@ procedure TMyApplication.DumpGlyphIndex;
   Writeln('  U+0048 (H) = ', Format('%d  (%0:4.4x)', [FFontFile.Chars[$0048]]));
   writeln;
   Writeln('Glyph widths:');
-  Writeln('  3 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0020]].AdvanceWidth));
-  Writeln('  4 = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0021]].AdvanceWidth));
-  Writeln('  H = ', TFriendClass(FFontFile).ToNatural(FFontFile.Widths[FFontFile.Chars[$0048]].AdvanceWidth));
+  PrintGlyphWidth($0020);
+  PrintGlyphWidth($0021);
+  PrintGlyphWidth($0048);
 end;
 
 function TMyApplication.GetGlyphIndices(const AText: UnicodeString): TTextMappingList;
@@ -121,6 +136,7 @@ procedure TMyApplication.DoRun;
   end;
 
   FFontFile.LoadFromFile(self.GetOptionValue('f'));
+  Writeln('Postscript.IsFixedPitch = ', BoolToStr(FFontFile.PostScript.isFixedPitch > 0, True));
   DumpGlyphIndex;
 
   // test #1
-- 
2.17.1

Graeme Geldenhuys

2019-03-21 17:22

reporter   ~0114965

I've attached two pathes.
  * One fixes the range check error in the ttfdump utility app.
  * The other one fixes the Glyph AdvanceWidth handling of monospaced fonts, also
    preventing a range check error.

This seems to resolve this issue for me.

The patches are against FPC Trunk r41755, but I recommend this gets backported to FPC 3.0.4 (fixes branch) too - if possible.

Michael Van Canneyt

2019-03-26 22:37

administrator   ~0115069

Applied Graeme's patched, please test and close if OK

LacaK

2019-03-27 07:19

developer   ~0115075

Last edited: 2019-03-27 07:23

View 3 revisions

There is still unresolved spacing issue in case when embedded fonts are used (test-embed2.pdf compare to test-noembed2.pdf). Was reported on ML ...
And /MissingWidth has wrong value (which should not be used so probably has no negative impact on document rendering, but still may signals problem)

LacaK

2019-03-27 07:19

developer  

test-embed2.pdf (39,109 bytes)

LacaK

2019-03-27 07:20

developer  

test-noembed2.pdf (5,040 bytes)

Issue History

Date Modified Username Field Change
2019-03-20 09:34 LacaK New Issue
2019-03-20 09:34 LacaK File Added: test_fpPDF.lpr
2019-03-20 09:35 LacaK File Added: test.pdf
2019-03-20 09:36 LacaK File Added: CourierNew.PNG
2019-03-20 09:45 LacaK Summary Writing text in "Courier New" TTF font generates wrong PDF document => fcl-pdf: Writing text in "Courier New" TTF font generates wrong PDF document
2019-03-20 09:45 LacaK Tag Attached: fcl-pdf
2019-03-20 09:45 LacaK Tag Attached: fpPDF
2019-03-21 09:38 LacaK File Added: test-noembed.pdf
2019-03-21 09:40 LacaK Note Added: 0114956
2019-03-21 09:47 LacaK Note Edited: 0114956 View Revisions
2019-03-21 11:04 LacaK Note Edited: 0114956 View Revisions
2019-03-21 17:18 Graeme Geldenhuys File Added: 0001-fppdf-fixes-glyph-width-range-check-error-for-monosp.patch
2019-03-21 17:19 Graeme Geldenhuys File Added: 0002-fcl-pdf-ttfdump-fixes-glyph-width-range-check-error-.patch
2019-03-21 17:22 Graeme Geldenhuys Note Added: 0114965
2019-03-22 11:28 Michael Van Canneyt Assigned To => Michael Van Canneyt
2019-03-22 11:28 Michael Van Canneyt Status new => assigned
2019-03-26 22:37 Michael Van Canneyt Fixed in Revision => 41800
2019-03-26 22:37 Michael Van Canneyt Note Added: 0115069
2019-03-26 22:37 Michael Van Canneyt Status assigned => resolved
2019-03-26 22:37 Michael Van Canneyt Fixed in Version => 3.3.1
2019-03-26 22:37 Michael Van Canneyt Resolution open => fixed
2019-03-26 22:37 Michael Van Canneyt Target Version => 3.2.0
2019-03-27 07:19 LacaK Note Added: 0115075
2019-03-27 07:19 LacaK Status resolved => feedback
2019-03-27 07:19 LacaK Resolution fixed => reopened
2019-03-27 07:19 LacaK Status feedback => acknowledged
2019-03-27 07:19 LacaK File Added: test-embed2.pdf
2019-03-27 07:20 LacaK File Added: test-noembed2.pdf
2019-03-27 07:22 LacaK Note Edited: 0115075 View Revisions
2019-03-27 07:23 LacaK Note Edited: 0115075 View Revisions
2019-12-05 16:08 Michael Van Canneyt Target Version 3.2.0 =>
2019-12-05 16:08 Michael Van Canneyt FPCTarget => -