我想通过将HTML内容传递给函数来生成PDF。我已经为此使用了iTextSharp,但它在遇到表和布局时表现不佳。

有没有更好的办法?


当前回答

你可以使用WebBrowser控件的另一个技巧,下面是我的完整工作代码

在我的例子中,为文本框控件分配Url

  protected void Page_Load(object sender, EventArgs e)
{

   txtweburl.Text = "https://www.google.com/";

 }

下面是使用线程生成屏幕的代码

  protected void btnscreenshot_click(object sender, EventArgs e)
  {
    //  btnscreenshot.Visible = false;
    allpanels.Visible = true;
    Thread thread = new Thread(GenerateThumbnail);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();

}

private void GenerateThumbnail()
{
    //  btnscreenshot.Visible = false;
    WebBrowser webrowse = new WebBrowser();
    webrowse.ScrollBarsEnabled = false;
    webrowse.AllowNavigation = true;
    string url = txtweburl.Text.Trim();
    webrowse.Navigate(url);
    webrowse.Width = 1400;
    webrowse.Height = 50000;

    webrowse.DocumentCompleted += webbrowse_DocumentCompleted;
    while (webrowse.ReadyState != WebBrowserReadyState.Complete)
    {
        System.Windows.Forms.Application.DoEvents();
    }
}

在下面的代码中,我下载后保存pdf文件

        private void webbrowse_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    // btnscreenshot.Visible = false;
    string folderPath = Server.MapPath("~/ImageFiles/");

    WebBrowser webrowse = sender as WebBrowser;
    //Bitmap bitmap = new Bitmap(webrowse.Width, webrowse.Height);

    Bitmap bitmap = new Bitmap(webrowse.Width, webrowse.Height, PixelFormat.Format16bppRgb565);

    webrowse.DrawToBitmap(bitmap, webrowse.Bounds);


    string Systemimagedownloadpath = System.Configuration.ConfigurationManager.AppSettings["Systemimagedownloadpath"].ToString();
    string fullOutputPath = Systemimagedownloadpath + Request.QueryString["VisitedId"].ToString() + ".png";
    MemoryStream stream = new MemoryStream();
    bitmap.Save(fullOutputPath, System.Drawing.Imaging.ImageFormat.Jpeg);



    //generating pdf code 
     Document pdfDoc = new Document(new iTextSharp.text.Rectangle(1100f, 20000.25f));
     PdfWriter writer = PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
     pdfDoc.Open();
     iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(fullOutputPath);   
     img.ScaleAbsoluteHeight(20000);
     img.ScaleAbsoluteWidth(1024);     
     pdfDoc.Add(img);
     pdfDoc.Close();
     //Download the PDF file.
     Response.ContentType = "application/pdf";
     Response.AddHeader("content-disposition", "attachment;filename=ImageExport.pdf");
     Response.Cache.SetCacheability(HttpCacheability.NoCache);
     Response.Write(pdfDoc);
     Response.End();


}

你也可以参考我最老的帖子了解更多信息:在asp.net web表单中导航到网页被取消了

其他回答

对于所有在。net 5及以上版本中寻找工作解决方案的人,请访问这里。

以下是我的工作解决方案。

使用wkhtmltopdf:

从这里下载并安装最新版本的wkhtmltopdf。 使用下面的代码。

public static string HtmlToPdf(string outputFilenamePrefix, string[] urls,
    string[] options = null,
    string pdfHtmlToPdfExePath = @"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe")
{
    string urlsSeparatedBySpaces = string.Empty;
    try
    {
        //Determine inputs
        if ((urls == null) || (urls.Length == 0))
            throw new Exception("No input URLs provided for HtmlToPdf");
        else
            urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs

        string outputFilename = outputFilenamePrefix + "_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss-fff") + ".PDF"; // assemble destination PDF file name

        var p = new System.Diagnostics.Process()
        {
            StartInfo =
            {
                FileName = pdfHtmlToPdfExePath,
                Arguments = ((options == null) ? "" : string.Join(" ", options)) + " " + urlsSeparatedBySpaces + " " + outputFilename,
                UseShellExecute = false, // needs to be false in order to redirect output
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
                WorkingDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location))
            }
        };

        p.Start();

        // read the output here...
        var output = p.StandardOutput.ReadToEnd();
        var errorOutput = p.StandardError.ReadToEnd();

        // ...then wait n milliseconds for exit (as after exit, it can't read the output)
        p.WaitForExit(60000);

        // read the exit code, close process
        int returnCode = p.ExitCode;
        p.Close();

        // if 0 or 2, it worked so return path of pdf
        if ((returnCode == 0) || (returnCode == 2))
            return outputFilename;
        else
            throw new Exception(errorOutput);
    }
    catch (Exception exc)
    {
        throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilenamePrefix, exc);
    }
}

并调用上述方法HtmlToPdf("test", new string[] {"https://www.google.com"}, new string[] {"-s A5"}); 如果你需要将HTML字符串转换为PDF,调整上述方法,并将参数替换为进程StartInfo为$@"/C echo | set /p=""{htmlText}"" | ""{pdfHtmlToPdfExePath}""{((选项== null) ?"":字符串。加入(“”,选项))}-”“C: \用户桌面\ xxxx \ \ {outputFilename}”“”;

这种方法的缺点:

wkhtmltopdf的最新版本不支持最新的HTML5和CSS3。因此,如果您尝试将任何html导出为CSS GRID,那么输出将不会像预期的那样。 您需要处理并发性问题。

使用铬无头:

从这里下载并安装最新的chrome浏览器。 使用下面的代码。

var p = new System.Diagnostics.Process()
{
    StartInfo =
    {
        FileName = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe",
        Arguments = @"/C --headless --disable-gpu --run-all-compositor-stages-before-draw --print-to-pdf-no-header --print-to-pdf=""C:/Users/Abdul Rahman/Desktop/test.pdf"" ""C:/Users/Abdul Rahman/Desktop/grid.html""",
    }
};

p.Start();

// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);

// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();

这将把html文件转换为pdf文件。 如果你需要将一些url转换为pdf,那么使用下面的参数来处理StartInfo

@"/C——headless——disable-gpu——run-all- composter - stagebefore -draw——print-to-pdf-no-header——print-to-pdf=""C:/Users/Abdul Rahman/Desktop/test.pdf"" ""https://www.google.com"",

这种方法的缺点:

这与最新的HTML5和CSS3特性一样。输出将与您在浏览器中查看的相同,但当通过IIS运行时,您需要在LocalSystem Identity下运行应用程序的AppliactionPool,或者您需要提供对IISUSRS的读写访问。

使用Selenium WebDriver:

安装Nuget包硒。WebDriver和Selenium.WebDriver.ChromeDriver。 使用下面的代码。

public async Task<byte[]> ConvertHtmlToPdf(string html)
{
    var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "ApplicationName");
    Directory.CreateDirectory(directory);
    var filePath = Path.Combine(directory, $"{Guid.NewGuid()}.html");
    await File.WriteAllTextAsync(filePath, html);

    var driverOptions = new ChromeOptions();
    // In headless mode, PDF writing is enabled by default (tested with driver major version 85)
    driverOptions.AddArgument("headless");
    using var driver = new ChromeDriver(driverOptions);
    driver.Navigate().GoToUrl(filePath);

    // Output a PDF of the first page in A4 size at 90% scale
    var printOptions = new Dictionary<string, object>
    {
        { "paperWidth", 210 / 25.4 },
        { "paperHeight", 297 / 25.4 },
        { "scale", 0.9 },
        { "pageRanges", "1" }
    };
    var printOutput = driver.ExecuteChromeCommandWithResult("Page.printToPDF", printOptions) as Dictionary<string, object>;
    var pdf = Convert.FromBase64String(printOutput["data"] as string);

    File.Delete(filePath);

    return pdf;
}

该方法的优点:

这只需要一个Nuget安装和工作与最新的HTML5和CSS3功能预期。输出将与您在浏览器中查看的相同。

这种方法的缺点:

这种方法需要在应用程序运行的服务器上安装最新的chrome浏览器。 如果服务器中的chrome浏览器版本更新,则需要更新Selenium.WebDriver.ChromeDriver Nuget包。否则,由于版本不匹配,将抛出运行时错误。

使用这种方法,请确保在.csproj文件中添加<PublishChromeDriver>true</PublishChromeDriver>,如下所示:

<PropertyGroup>
  <TargetFramework>net5.0</TargetFramework>
  <LangVersion>latest</LangVersion>
  <Nullable>enable</Nullable>
  <PublishChromeDriver>true</PublishChromeDriver>
</PropertyGroup>

这将在发布项目时发布chrome驱动程序。

这是我的工作项目repo - HtmlToPdf的链接

使用JavaScript中的window.print()从浏览器生成PDF

如果用户从浏览器使用你的应用程序,那么你可以依靠JavaScript和使用window.print()和必要的打印媒体css从浏览器生成PDF。例如,生成发票从浏览器在一个库存应用程序。

该方法的优点:

不依赖于任何工具。 在浏览器中直接从HTML, CSS和JS生成PDF。 快 支持所有最新的CSS属性。

这种方法的缺点:

在像Blazor这样的SPA中,我们需要使用iframe来打印页面的部分。

在几乎花了2天的时间与可用的选项之后,我得到了上面的答案,最终实现了基于Selenium的解决方案,它正在工作。希望这能帮到你,节省你的时间。

到目前为止,似乎最好的免费。net解决方案是TuesPechkin库,它是wkhtmltopdf本机库的包装。

我现在已经使用单线程版本将几千个HTML字符串转换为PDF文件,它似乎工作得很好。它应该也可以在多线程环境中工作(例如IIS),但我还没有对此进行测试。

另外,因为我想使用最新版本的wkhtmltopdf(在编写时为0.12.5),我从官方网站下载了DLL,复制到我的项目根目录,设置copy to output为true,并像这样初始化库:

var dllDir = AppDomain.CurrentDomain.BaseDirectory;
Converter = new StandardConverter(new PdfToolset(new StaticDeployment(dllDir)));

上面的代码看起来完全是“wkhtmltox.dll”,所以不要重命名文件。我使用的是64位版本的DLL。

确保你阅读了多线程环境的说明,因为你只需要在每个应用生命周期中初始化它一次,所以你需要把它放在一个单例或其他东西中。

我之前也在找这个。我遇到了HTMLDOC http://www.easysw.com/htmldoc/,这是一个免费的开源命令行应用程序,它以HTML文件为参数,并从中输出PDF。这在我的副业项目中非常有效,但这完全取决于你真正需要什么。

制作它的公司出售编译后的二进制文件,但您可以免费从源代码下载和编译并使用它。我设法编译了一个最近的版本(1.9版本),我打算在几天内发布它的二进制安装程序,所以如果你感兴趣,我可以在发布它时立即提供它的链接。

编辑(2/25/2014):看起来文档和网站转移到http://www.msweet.org/projects.php?Z1

最后更新:2020年10月

这是我整理的。net中HTML到PDF转换的选项列表(有些是免费的,有些是付费的)

GemBox.Document https://www.nuget.org/packages/GemBox.Document/ Free (up to 20 paragraphs) $680 - https://www.gemboxsoftware.com/document/pricelist https://www.gemboxsoftware.com/document/examples/c-sharp-convert-html-to-pdf/307 PDF Metamorphosis .Net https://www.nuget.org/packages/sautinsoft.pdfmetamorphosis/ $539 - $1078 - https://www.sautinsoft.com/products/pdf-metamorphosis/order.php https://www.sautinsoft.com/products/pdf-metamorphosis/convert-html-to-pdf-dotnet-csharp.php HtmlRenderer.PdfSharp https://www.nuget.org/packages/HtmlRenderer.PdfSharp/1.5.1-beta1 BSD-UNSPECIFIED License PuppeteerSharp https://www.puppeteersharp.com/examples/index.html MIT License https://github.com/kblok/puppeteer-sharp EO.Pdf https://www.nuget.org/packages/EO.Pdf/ $799 - https://www.essentialobjects.com/Purchase.aspx?f=3 WnvHtmlToPdf_x64 https://www.nuget.org/packages/WnvHtmlToPdf_x64/ $750 - $1600 - http://www.winnovative-software.com/Buy.aspx demo - http://www.winnovative-software.com/demo/default.aspx IronPdf https://www.nuget.org/packages/IronPdf/ $399 - $1599 - https://ironpdf.com/licensing/ https://ironpdf.com/examples/using-html-to-create-a-pdf/ Spire.PDF https://www.nuget.org/packages/Spire.PDF/ Free (up to 10 pages) $599 - $1799 - https://www.e-iceblue.com/Buy/Spire.PDF.html https://www.e-iceblue.com/Tutorials/Spire.PDF/Spire.PDF-Program-Guide/Convert-HTML-to-PDF-Customize-HTML-to-PDF-Conversion-by-Yourself.html Aspose.Html https://www.nuget.org/packages/Aspose.Html/ $599 - $1797 - https://purchase.aspose.com/pricing/html/net https://docs.aspose.com/html/net/html-to-pdf-conversion/ EvoPDF https://www.nuget.org/packages/EvoPDF/ $450 - $1200 - http://www.evopdf.com/buy.aspx ExpertPdfHtmlToPdf https://www.nuget.org/packages/ExpertPdfHtmlToPdf/ $550 - $1200 - https://www.html-to-pdf.net/Pricing.aspx Zetpdf https://zetpdf.com $299 - $599 - https://zetpdf.com/pricing/ Is not a well know or supported library - ZetPDF - Does anyone know the background of this Product? PDFtron https://www.pdftron.com/documentation/samples/cs/HTML2PDFTes $4000/year - https://www.pdftron.com/licensing/ WkHtmlToXSharp https://github.com/pruiz/WkHtmlToXSharp Free Concurrent conversion is implemented as processing queue. SelectPDF https://www.nuget.org/packages/Select.HtmlToPdf/ Free (up to 5 pages) $499 - $799 - https://selectpdf.com/pricing/ https://selectpdf.com/pdf-library-for-net/

如果上面的选项都帮不了你,你可以搜索NuGet包: https://www.nuget.org/packages?q=html+pdf

你可以使用WebBrowser控件的另一个技巧,下面是我的完整工作代码

在我的例子中,为文本框控件分配Url

  protected void Page_Load(object sender, EventArgs e)
{

   txtweburl.Text = "https://www.google.com/";

 }

下面是使用线程生成屏幕的代码

  protected void btnscreenshot_click(object sender, EventArgs e)
  {
    //  btnscreenshot.Visible = false;
    allpanels.Visible = true;
    Thread thread = new Thread(GenerateThumbnail);
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();

}

private void GenerateThumbnail()
{
    //  btnscreenshot.Visible = false;
    WebBrowser webrowse = new WebBrowser();
    webrowse.ScrollBarsEnabled = false;
    webrowse.AllowNavigation = true;
    string url = txtweburl.Text.Trim();
    webrowse.Navigate(url);
    webrowse.Width = 1400;
    webrowse.Height = 50000;

    webrowse.DocumentCompleted += webbrowse_DocumentCompleted;
    while (webrowse.ReadyState != WebBrowserReadyState.Complete)
    {
        System.Windows.Forms.Application.DoEvents();
    }
}

在下面的代码中,我下载后保存pdf文件

        private void webbrowse_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    // btnscreenshot.Visible = false;
    string folderPath = Server.MapPath("~/ImageFiles/");

    WebBrowser webrowse = sender as WebBrowser;
    //Bitmap bitmap = new Bitmap(webrowse.Width, webrowse.Height);

    Bitmap bitmap = new Bitmap(webrowse.Width, webrowse.Height, PixelFormat.Format16bppRgb565);

    webrowse.DrawToBitmap(bitmap, webrowse.Bounds);


    string Systemimagedownloadpath = System.Configuration.ConfigurationManager.AppSettings["Systemimagedownloadpath"].ToString();
    string fullOutputPath = Systemimagedownloadpath + Request.QueryString["VisitedId"].ToString() + ".png";
    MemoryStream stream = new MemoryStream();
    bitmap.Save(fullOutputPath, System.Drawing.Imaging.ImageFormat.Jpeg);



    //generating pdf code 
     Document pdfDoc = new Document(new iTextSharp.text.Rectangle(1100f, 20000.25f));
     PdfWriter writer = PdfWriter.GetInstance(pdfDoc, Response.OutputStream);
     pdfDoc.Open();
     iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(fullOutputPath);   
     img.ScaleAbsoluteHeight(20000);
     img.ScaleAbsoluteWidth(1024);     
     pdfDoc.Add(img);
     pdfDoc.Close();
     //Download the PDF file.
     Response.ContentType = "application/pdf";
     Response.AddHeader("content-disposition", "attachment;filename=ImageExport.pdf");
     Response.Cache.SetCacheability(HttpCacheability.NoCache);
     Response.Write(pdfDoc);
     Response.End();


}

你也可以参考我最老的帖子了解更多信息:在asp.net web表单中导航到网页被取消了