Converting HTML to PDF in Linux Return NullReferenceException

We are using Aspose.HTML to Convert HTML content to PDF in our Lambda Functions which are hosted in Linux.

Aspose.HTML are supposed to be cross-platform but we are receiving NullReferenceException when running in Linux, we don’t encounter any error if we run the functions in windows.

Here’s the code:

public byte[] GeneratePdf(string data)
{
    var license = new License();
    license.SetLicense("Aspose.Total.NET.lic");

    using var document = new HTMLDocument(data, string.Empty);

    var options = new PdfSaveOptions {
        PageSetup =
        {
            AnyPage = new Page(new Size(1203,403),
                new Margin(0, 0, 0, 0))
        }
    };

    using var streamProvider = new MemoryStreamProvider();

    Converter.ConvertHTML(document, options, streamProvider);

    return streamProvider.Streams[0].ToArray();
}

Here’s the error we got:

System.NullReferenceException: Object reference not set to an instance of an object.
   at ​  .​   ​ (   , Char )
   at    .(    ,    ,     )
   at    ..ctor(    , IBrowsingContext ,    )
   at    ..ctor(Node ,    ,     )
   at    .(Element ,     ,     , ​   ,     ,     )
   at    .(Element ,     ,     ,     )
   at    .(Document , RenderingOptions , IDevice , ​   ,     , ​  )
   at    .​   ​ (IDevice , ​   )
   at    .()
   at    .    ​ (Renderer , ​  [] , IDevice , CancellationToken )
   at Aspose.Html.Rendering.HtmlRenderer.(IDevice , CancellationToken , Element[] , Document[] )
   at Aspose.Html.Rendering.HtmlRenderer.Render(IDevice device, TimeSpan timeout, HTMLDocument[] sources)
   at   .(   , IDevice )
   at   .   ​ (   , ImageSaveOptions , ICreateStreamProvider )
   at Aspose.Html.Converters.Converter.ConvertHTML(HTMLDocument document, ImageSaveOptions options, ICreateStreamProvider provider)
   at AIG.Travel.CloudPlayground.Services.AsposeHtmlService.GeneratePng(String data) in D:\BDF\F01A\6\s\src\AIG.Travel.CloudPlayground.Services\AsposeHtmlService.cs:line 56
   at AIG.Travel.CloudPlayground.Lambdas.AsposeHtml.GeneratePng(IAsposeHtmlService asposeHtmlService) in D:\BDF\F01A\6\s\src\AIG.Travel.CloudPlayground\Lambdas\AsposeHtml.cs:line 25
   at AIG.Travel.CloudPlayground.Lambdas.AsposeHtml_GeneratePng_Generated.GeneratePng(APIGatewayProxyRequest __request__, ILambdaContext __context__) in D:\BDF\F01A\6\s\src\AIG.Travel.CloudPlayground\obj\Release\net8.0\linux-x64\generated\Liberty.Logging.Lambda.Annotations.SourceGenerator\Liberty.Logging.Lambda.Annotations.SourceGenerator.Generator\AsposeHtml_GeneratePng_Generated.g.cs:line 63
   at lambda_method1(Closure, Stream, ILambdaContext, Stream)
   at Amazon.Lambda.RuntimeSupport.HandlerWrapper.<>c__DisplayClass8_0.<GetHandlerWrapper>b__0(InvocationRequest invocation) in /src/Repo/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/HandlerWrapper.cs:line 54
   at Amazon.Lambda.RuntimeSupport.LambdaBootstrap.InvokeOnceAsync(CancellationToken cancellationToken) in /src/Repo/Libraries/src/Amazon.Lambda.RuntimeSupport/Bootstrap/LambdaBootstrap.cs:line 185

@kbdev

It seems you are encountering a NullReferenceException when trying to convert HTML to PDF using Aspose.HTML in a Linux environment, while it works fine on Windows. This issue could be related to several factors, including differences in the environment or the way resources are handled in Linux.

Here are a few suggestions to troubleshoot and potentially resolve the issue:

  1. Check License File Path: Ensure that the license file path is correctly set and accessible in the Linux environment. Sometimes, file paths can differ between operating systems.

  2. HTML Content: Verify that the HTML content you are passing to the HTMLDocument constructor is valid and not null. If the HTML content is dynamically generated, ensure that it is being generated correctly in the Linux environment.

  3. Dependencies: Make sure that all necessary dependencies and libraries required by Aspose.HTML are properly installed and configured in your Linux environment. Sometimes, missing dependencies can lead to unexpected exceptions.

  4. MemoryStreamProvider: Ensure that the MemoryStreamProvider is being used correctly. You might want to check if the streams are being created and accessed properly.

  5. Debugging: Add logging or debugging statements to identify exactly where the NullReferenceException is being thrown. This can help you pinpoint the issue more effectively.

  6. Example Code: You can refer to example implementations provided in the Aspose documentation or GitHub repository. For instance, there are examples that demonstrate how to convert HTML to PDF using a MemoryStreamProvider, which might help you identify any discrepancies in your implementation.

Here is a simplified example of converting HTML to PDF using a MemoryStreamProvider:

using Aspose.Html;
using Aspose.Html.Saving;
using System.IO;

public byte[] GeneratePdf(string data)
{
    var license = new License();
    license.SetLicense("Aspose.Total.NET.lic");

    using var document = new HTMLDocument(data, string.Empty);
    var options = new PdfSaveOptions();

    using var streamProvider = new MemoryStreamProvider();
    Converter.ConvertHTML(document, options, streamProvider);

    return streamProvider.Streams[0].ToArray();
}

If the issue persists after trying these suggestions, consider reaching out to Aspose support with detailed information about your environment and the specific HTML content you are trying to convert.

Sources:
[1]: ConvertHTMLToPDF.cs

We are able to run it without an error win Windows, so I think the License Path, HTMLContent, Memory StreamProvider are working.

We already tried adding a logging, and looks like the error encountered here:

Converter.ConvertHTML(document, options, streamProvider);

@kbdev

If possible, could you please share the sample HTML in .zip format as well as the complete version information of the Linux environment?

We are only testing it on a straightforward static html:

<html><body>test</body></html>

The runtime is dotnet8.0, this are lambda functions running in Linux

@kbdev

We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): HTMLNET-5813

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Hello, when can we expect to have an updates on this?

@kbdev

The issue has recently been logged in our issue tracking system and it will be prioritized on a first come first serve basis. As soon as we make some progress towards its resolution, we will inform you. Please be patient and spare us some time. We are sorry for the inconvenience.

The issues you have found earlier (filed as HTMLNET-5813) have been fixed in this update. This message was posted using Bugs notification tool by avpavlysh

@kbdev

We have investigated this issue. It occurs because a font can’t be found following the default system font locations. We’ll provide a more informative exception to mark this case in the nearest release.

To bypass this problem, we propose 2 possible ways to customize the font source:

  1. manually place needed fonts to the local file system folder and set it as a parameter of SetFontsLookupFolder method, as it is shown in the code snippet below; also see documentation page as follows:
    Aspose.HTML for .NET
        public void Run()
        {
            var content = "<html><body>test</body></html>";
            var config = new Configuration();
 
            var service = config.GetService<IUserAgentService>();
            service.FontsSettings.SetFontsLookupFolder(Path.Combine(@"/home/myaccount/my_custom_fonts"));
 
            using (var document = new HTMLDocument(content, string.Empty, config))
            using (var streamProvider = new MemoryStreamProvider())
            {
                var options = new PdfSaveOptions();
                Converter.ConvertHTML(document, options, streamProvider);
                // ...
            }
        }
  1. use custom font substitution by setting the FontMatcher property; for this, you should define your custom class inherited from FontMatcher to override its default behavior. This method supports TTF/TTC fonts; in the nearest release we’ll add support of WOFF/WOFF2.

There are also 2 ways to do that:

  • load the font from local file system - see code snippet below:
        public void Run_1()
        {
            var content = "<html><body>test</body></html>";
            var config = new Configuration();
 
            config.GetService<IUserAgentService>().FontsSettings.FontMatcher = new CustomFontMatcher();
 
            using (var document = new HTMLDocument(content, string.Empty, config))
            using (var streamProvider = new MemoryStreamProvider())
            {
                var options = new PdfSaveOptions();
                Converter.ConvertHTML(document, options, streamProvider);
            }
        }
		....
		class CustomFontMatcher : FontMatcher
        {
            private byte[] font;
            private string[] fontsFolders = new string[] {
                @"d:\my_custom_fonts"
            };
 
            public CustomFontMatcher()
            {
                font = File.ReadAllBytes(Path.Combine(fontsFolders[0], "arial.ttf"));
            }
 
            public override byte[] MatchFontFallback(FontMatchingProperties fontMatchingProperties, uint charCode)
            {
                return font;
            }
        }
  • download programmatically the font by a web path as a byte array and use it for the font substitution - see code snippet below:
        public void Run_2()
        {
            var content = "<html><body>test</body></html>";
            var fontPath = "https://fonts.gstatic.com/s/opensans/v40/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2";
 
            var config = new Configuration();
 
            using (var document = new HTMLDocument(content, string.Empty, config))
            using (var streamProvider = new MemoryStreamProvider())
            {
                config.GetService<IUserAgentService>().FontsSettings.FontMatcher = 
                    new SubsitutionFontMatcher(document.Context, fontPath);
 
                var options = new PdfSaveOptions();
                Converter.ConvertHTML(document, options, streamProvider);
                // ...               
            }
        }
		....
        class SubsitutionFontMatcher : FontMatcher
        {
            private byte[] font;
 
            public SubsitutionFontMatcher(IBrowsingContext context, string fontPath)
            {
                var response = context.Network.Send(new Net.RequestMessage(fontPath));
                if (response.IsSuccess)
                {
                    font = response.Content.ReadAsByteArray();
                }
                else
                {
                    throw new Exception("Cannot load a font by specified path");
                }
            }
 
            public override byte[] MatchFontFallback(FontMatchingProperties fontMatchingProperties, uint charCode)
            {
                return font;
            }
        }