PDFsharp & MigraDoc Foundation
http://forum.pdfsharp.com/

Font resolving is not thread safe
http://forum.pdfsharp.com/viewtopic.php?f=3&t=4511
Page 1 of 1

Author:  truthz03 [ Sun Nov 19, 2023 11:54 am ]
Post subject:  Font resolving is not thread safe

Hi,

I have tried to call this code in parallel because otherwise it is very slow to render all pages:
Code:
using (XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append))
{
    documentRenderer.RenderPage(gfx, pageIndex);
}


Sometimes it is working, so theoretically this is not a big problem.
But sometimes it fails with the following error:
Quote:
System.InvalidOperationException: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct. at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
at PdfSharp.Pdf.Advanced.PdfFontTable.GetFont(XFont font)
at PdfSharp.Pdf.PdfPage.GetFontName(XFont font, PdfFont& pdfFont)
at PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer.GetFontName(XFont font, PdfFont& pdfFont)
at PdfSharp.Drawing.Pdf.PdfGraphicsState.RealizeFont(XFont font, XBrush brush, Int32 renderingMode)
at PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer.Realize(XFont font, XBrush brush, Int32 renderingMode)
at PdfSharp.Drawing.Pdf.XGraphicsPdfRenderer.DrawString(String s, XFont font, XBrush brush, XRect rect, XStringFormat format)
at PdfSharp.Drawing.XGraphics.DrawString(String text, XFont font, XBrush brush, XRect layoutRectangle, XStringFormat format)
at PdfSharp.Drawing.XGraphics.DrawString(String s, XFont font, XBrush brush, Double x, Double y)
at MigraDoc.Rendering.ParagraphRenderer.RenderWord(String word)
at MigraDoc.Rendering.ParagraphRenderer.RenderText(Text text)
at MigraDoc.Rendering.ParagraphRenderer.RenderElement(DocumentObject docObj)
at MigraDoc.Rendering.ParagraphRenderer.RenderLine(LineInfo lineInfo)
at MigraDoc.Rendering.ParagraphRenderer.Render()
at MigraDoc.Rendering.DocumentRenderer.RenderHeader(XGraphics graphics, Int32 page)
at MigraDoc.Rendering.DocumentRenderer.RenderPage(XGraphics gfx, Int32 page, PageRenderOptions options)
at MigraDoc.Rendering.DocumentRenderer.RenderPage(XGraphics gfx, Int32 page)


Is it possible to make this specific Dictionary thread safe?
Or can I add all fonts before starting the rendering?

Thanks
Thomas

Author:  TH-Soft [ Mon Nov 20, 2023 4:58 am ]
Post subject:  Re: Font resolving is not thread safe

Are you using version 6.0.0?

See also:
http://forum.pdfsharp.net/viewtopic.php?f=2&t=832

Author:  TH-Soft [ Mon Nov 20, 2023 6:26 am ]
Post subject:  Re: Font resolving is not thread safe

truthz03 wrote:
Is it possible to make this specific Dictionary thread safe?
PDFsharp is meant to be threadsafe and locks are used for font handling, but only a single thread must be used per document.
MigraDoc is not meant to be thread safe and just a single thread should be used to render all pages.

I don't have time to investigate this (non-)issue this month.
If you get it working with a few locks, please share your code changes here.
This is not my area of expertise and I cannot estimate how complicated this may get.

Author:  truthz03 [ Mon Nov 20, 2023 11:43 am ]
Post subject:  Re: Font resolving is not thread safe

Thanks for your answer.
Yes I'm using 6.0.0

I have downloaded the source code from "Branch_v6.0.0" now and tried to fix the problem.
Changing these things inside the PdfFontTable class will fix the error above
Code:
        /// <summary>
        /// Gets a PdfFont from an XFont. If no PdfFont already exists, a new one is created.
        /// </summary>
        public PdfFont GetFont(XFont font)
        {
            var selector = font.Selector;
            if (selector == null)
            {
                selector = ComputeKey(font); //new FontSelector(font);
                font.Selector = selector;
            }

            var pdfFont = _fonts.GetOrAdd(selector, (selector) =>
            {
                PdfFont pdfFont;
                if (font.Unicode)
                    pdfFont = new PdfType0Font(Owner, font, font.IsVertical);
                else
                    pdfFont = new PdfTrueTypeFont(Owner, font);
                //pdfFont.Document = _document;
                Debug.Assert(pdfFont.Owner == Owner);
                return pdfFont;
            });
            return pdfFont;
        }

#if true
        /// <summary>
        /// Gets a PdfFont from a font program. If no PdfFont already exists, a new one is created.
        /// </summary>
        public PdfFont GetFont(string idName, byte[] fontData)
        {
            Debug.Assert(false);
            //FontSelector selector = new FontSelector(idName);
            string selector = null; // ComputeKey(font); //new FontSelector(font);
            var pdfFont = _fonts.GetOrAdd(selector, (selector) =>
            {
                PdfFont pdfFont;
                //if (font.Unicode)
                pdfFont = new PdfType0Font(Owner, idName, fontData, false);
                //else
                //  pdfFont = new PdfTrueTypeFont(_owner, font);
                //pdfFont.Document = _document;
                Debug.Assert(pdfFont.Owner == Owner);
                return pdfFont;
            });
            return pdfFont;
        }
#endif

        /// <summary>
        /// Map from PdfFontSelector to PdfFont.
        /// </summary>
        readonly ConcurrentDictionary<string, PdfFont> _fonts = new ConcurrentDictionary<string, PdfFont>();

but than I get other errors.

It would be nice to be able to render pages of a single document in parallel, but I think there has to be more changes.

Maybe this could be a feature for a later version

Page 1 of 1 All times are UTC
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/