Skip to content

Replace SixLabors.Fonts with SkiaSharp for text measurement#1717

Merged
tonyqus merged 4 commits into
masterfrom
copilot/fix-font-null-reference
Mar 6, 2026
Merged

Replace SixLabors.Fonts with SkiaSharp for text measurement#1717
tonyqus merged 4 commits into
masterfrom
copilot/fix-font-null-reference

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 6, 2026

SixLabors.Fonts 1.0.1 has unfixed bugs with certain fonts (e.g. NullReferenceException in the GSUB substitution engine for fonts like "B Nazanin"), and upgrading to 2.x is blocked because 2.x dropped .NET Standard 2.0/2.1 support.

Replacement: SkiaSharp 2.88.9

  • SkiaSharp replaces SixLabors.Fonts for all text measurement and font resolution
  • SkiaSharp.NativeAssets.Linux.NoDependencies added explicitly — SkiaSharp auto-includes Win32 and macOS native assets as transitive deps but deliberately omits Linux; this variant requires only standard glibc components and works on all Linux distributions including minimal containers

Key API changes

SheetUtil.IFont2Font(IFont) now returns SKFont (disposable — callers must use using). Font size is stored in pixels (pointSize × dpi / 72); typeface resolution is cached separately keyed by (fontName, bold, italic).

// Before
Font wfont = SheetUtil.IFont2Font(font);
float width = TextMeasurer.MeasureSize(txt, new TextOptions(wfont) { Dpi = 96 }).Width;

// After
using SKFont wfont = SheetUtil.IFont2Font(font);
using var paint = new SKPaint { Typeface = wfont.Typeface, TextSize = wfont.Size };
float width = paint.MeasureText(txt);

Files changed

  • SheetUtil.csIFont2FontSKFont; TextMeasurerSKPaint.MeasureText; height uses SKFont.Size (em-square) to match prior MeasureAdvance line-height semantics; empty strings return 0 height
  • EscherGraphics.csFont/FontFamily/SystemFontsSKFont/SKTypeface; Font property type updated
  • HSSFSheet.csHSSFFont2Font() delegates to SheetUtil.IFont2Font
  • XSSFSheet.cs, XSSFClientAnchor.cs — inline TextMeasurer.MeasureSize("0", …)SKPaint.MeasureText("0")
  • FormulaParser.csSixLabors.Fonts.Unicode.CodePoint removed; replaced with char.IsLetter/IsDigit/IsLetterOrDigit via char.ConvertFromUtf32
Original prompt

This section details on the original issue you should resolve

<issue_title>Problem with font "BNazanin.ttf", System.NullReferenceException</issue_title>
<issue_description>### NPOI Version
2.7.4 (or whichever version uses SixLabors.Fonts 1.0.1)

File Type

  • XLSX
  • XLS
  • DOCX
  • XLSM
  • OTHER

Upload the Excel File

No file attached — issue can be reproduced with the code below.

Reproduce Steps

var workbook = new SXSSFWorkbook();
var sheet = (SXSSFSheet)workbook.CreateSheet("test");

var cell = sheet.CreateRow(0).CreateCell(0);
cell.SetCellValue("نام");

IFont font = workbook.CreateFont();
font.FontName = "B Nazanin"; 
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(font);

sheet.TrackColumnForAutoSizing(0);
sheet.AutoSizeColumn(0);
  1. Create a new SXSSFWorkbook and sheet.
  2. Add a cell with the value "نام".
  3. Set the font to "B Nazanin".
  4. Track column 0 for auto-sizing and call AutoSizeColumn(0).
  5. Observe crash.

Stack trace:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at SixLabors.Fonts.Tables.AdvancedTypographic.GSub.LookupType5Format2SubTable.TrySubstitution(FontMetrics fontMetrics, GSubTable table, GlyphSubstitutionCollection collection, Tag feature, Int32 index, Int32 count)
   at SixLabors.Fonts.Tables.AdvancedTypographic.GSub.LookupTable.TrySubstitution(FontMetrics fontMetrics, GSubTable table, GlyphSubstitutionCollection collection, Tag feature, Int32 index, Int32 count)
   at SixLabors.Fonts.Tables.AdvancedTypographic.GSubTable.ApplyFeature(FontMetrics fontMetrics, GlyphSubstitutionCollection collection, SkippingGlyphIterator& iterator, Tag& featureTag, ScriptClass current, Int32 index, Int32& count, Int32& i, Int32& collectionCount, Int32 maxCount, Int32 maxOperationsCount, Int32& currentOperations)
   at SixLabors.Fonts.Tables.AdvancedTypographic.GSubTable.ApplySubstitution(FontMetrics fontMetrics, GlyphSubstitutionCollection collection)
   at SixLabors.Fonts.StreamFontMetrics.ApplySubstitution(GlyphSubstitutionCollection collection)
   at SixLabors.Fonts.FileFontMetrics.ApplySubstitution(GlyphSubstitutionCollection collection)
   at SixLabors.Fonts.TextLayout.DoFontRun(ReadOnlySpan`1 text, Int32 start, IReadOnlyList`1 textRuns, Int32& textRunIndex, Int32& codePointIndex, Int32& bidiRunIndex, Boolean isFallbackRun, Font font, BidiRun[] bidiRuns, Dictionary`2 bidiMap, GlyphSubstitutionCollection substitutions, GlyphPositioningCollection positionings)
   at SixLabors.Fonts.TextLayout.ProcessText(ReadOnlySpan`1 text, TextOptions options)
   at SixLabors.Fonts.TextLayout.GenerateLayout(ReadOnlySpan`1 text, TextOptions options)
   at SixLabors.Fonts.TextMeasurer.MeasureSize(ReadOnlySpan`1 text, TextOptions options)
   at SixLabors.Fonts.TextMeasurer.MeasureSize(String text, TextOptions options)
   at NPOI.SS.Util.SheetUtil.GetCellWidth(Int32 defaultCharWidth, Int32 colspan, ICellStyle style, Double width, String str, Font windowsFont, ICell cell)
   at NPOI.SS.Util.SheetUtil.GetCellWidth(ICell cell, Int32 defaultCharWidth, DataFormatter formatter, Boolean useMergedCells)
   at NPOI.SS.Util.SheetUtil.GetColumnWidthForRow(IRow row, Int32 column, Int32 defaultCharWidth, DataFormatter formatter, Boolean useMergedCells)
   at NPOI.SS.Util.SheetUtil.GetColumnWidth(ISheet sheet, Int32 column, Boolean useMergedCells, Int32 firstRow, Int32 lastRow, Int32 maxRows)
   at NPOI.SS.Util.SheetUtil.GetColumnWidth(ISheet sheet, Int32 column, Boolean useMergedCells, Int32 maxRows)
   at NPOI.XSSF.Streaming.SXSSFSheet.AutoSizeColumn(Int32 column, Boolean useMergedCells)
   at NPOI.XSSF.Streaming.SXSSFSheet.AutoSizeColumn(Int32 column)

Issue Description

When using B Nazanin font with SXSSFWorkbook and calling AutoSizeColumn, NPOI crashes because it depends on SixLabors.Fonts 1.0.1, which contains a bug with this font.

This bug is fixed in SixLabors.Fonts 2.0.1: SixLabors/Fonts#364

Proposed fix: update NPOI’s dependency on SixLabors.Fonts to >= 2.0.1.</issue_description>

<agent_instructions>Help me check if this issue still exists in lastest master branch</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@tonyqus NPOI cannot upgrade SixLabors.Fonts to 2.x because SixLabors.Fonts 2.x only supports .NET 6. It doesn't even support .NET Standard 2.0 and .NET Standard 2.1

SixLabors/Fonts#361</comment_new>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

… like B Nazanin

Co-authored-by: tonyqus <772561+tonyqus@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix System.NullReferenceException with BNazanin font Handle NullReferenceException from SixLabors.Fonts 1.0.1 during AutoSizeColumn Mar 6, 2026
Copilot AI and others added 2 commits March 6, 2026 08:53
…handling

Co-authored-by: tonyqus <772561+tonyqus@users.noreply.github.com>
…0 not SemiBold=600)

Co-authored-by: tonyqus <772561+tonyqus@users.noreply.github.com>
Copilot AI changed the title Handle NullReferenceException from SixLabors.Fonts 1.0.1 during AutoSizeColumn Replace SixLabors.Fonts with SkiaSharp for cross-platform font measurement Mar 6, 2026
Copilot AI changed the title Replace SixLabors.Fonts with SkiaSharp for cross-platform font measurement Replace SixLabors.Fonts with SkiaSharp for text measurement Mar 6, 2026
@tonyqus tonyqus marked this pull request as ready for review March 6, 2026 09:22
@tonyqus tonyqus added this to the NPOI 2.8.0 milestone Mar 6, 2026
@tonyqus tonyqus merged commit 475d7df into master Mar 6, 2026
3 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Problem with font "BNazanin.ttf", System.NullReferenceException

2 participants