Flayms / Markdown2Pdf

.NET library for converting markdown to PDF.
https://www.nuget.org/packages/Markdown2Pdf/
MIT License
5 stars 1 forks source link

Problems running in docker container #39

Closed byrialsen closed 8 months ago

byrialsen commented 8 months ago

Hi

I have some problems converting from .md -> .pdf when I run my Blazor server in a docker containers.

CODE SNIPPET:

// get markdown file reference
string file = ReleaseFileFullPath;

// check file existence
if (!File.Exists(file))
{
    throw new FileNotFoundException($"Could not find file: '{file}'");
}

// convert markdown file to pdf
string tmpPdfFile = Path.GetTempFileName();
var options = new Markdown2PdfOptions()
{
    MarginOptions = new MarginOptions()
    {
        Top = "2cm",
        Bottom = "2cm",
        Left = "2cm",
        Right = "2cm"
    }   
};
Markdown2PdfConverter converter = new Markdown2PdfConverter(options);

await Task.Run(() => converter.Convert(file, tmpPdfFile)).ConfigureAwait(false);

The files are evaluated to this:

file: /app/ReleaseInfo.md tmpPdfFile : /tmp/tmpXiokNg.tmp

The source .md file EXISTS and the dest .tmp file is created but size is empty and the convert method fails. Any clues on what is wrong?

byrialsen commented 8 months ago

I have this stack trace:

at System. Net.HttpWebRequest.EndGetResponse(lAsyncResult asyncResult)
at System.Net.WebClient.CetWebResponse(WebRequest request, IAsyncResult result)
at System. Net.WebClient.GetWebResponseTaskAsync(WebRequest request)
at System.Net.WebClient.DownloadBitsAsync(WebRequest request, Stream writeStream, AsyncOperation asyncOp, Action 3 completionDelegate)

at PuppeteerSharp.BrowserFetcher.DownloadAsync(String revision) in /home/runner/work/puppeteer-sharp/puppeteer-sharp/lib/puppeteerSharp/BrowserFetcher.cs:line 264

at Markdown2Pdf.Markdown2PdfConverter—CreateBrowserAsync()
at Markdown2Pdf.Markdown2PdfConverter._GeneratePdfAsync(String htmlFilePath, String outputFilePath)
at Markdown2Pdf.Markdown2PdfConverter.Convert(String markdownFilePath, String outputFilePath)
at Cockpit.Core.Services.FileService.GetReleaselnfoBinaryPdfAsync(CancellationToken cancellationToken) in c:\projects\pc\colleqx2\cockpit\source\core\services\Fileservice.cs:line 114

Do I understand it correctly that this converter needs chromium to be available and inside docker container (Linux dist) this is not the case. Also my docker invironment is hosted on a closed eco-system without internet access, thus I can not use this component. Right ?

Flayms commented 8 months ago

Yeah you're right, this package uses PuppeteerSharp to render the PDF, which needs a headless chrome/-ium. Once you have chrome and the specified npm packages though, no internet access is needed.

I haven't completely tested the Linux support but I was assuming it works bc the Github tests are also running on Ubuntu. When I am testing the package with an Ubuntu 22.04 Docker Container though I am also getting the PuppeteerSharp Exception, even with Chromium installed.

Gonna investigate this further.

Flayms commented 8 months ago

Try using Markdown2Pdf v1.3.0 and add the following to your dockerfile (see running in docker):

RUN apt-get update \
    && apt-get install -y w3m \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

To run the container without internet access you also need to install chrome / chromium via the dockerfile. Then use Markdown2Pdf with the following options:

var options = new Markdown2PdfOptions {
  ChromePath = "path-to-chrome",
  ModuleOptions = ModuleOptions.FromLocalPath("path-to-node_modules"),
};

Note that without internet the node_modules also need to be installed seperately