告诉 abcPdf 缩放 html 以适合单个 pdf 页面

发布于 2024-08-19 02:30:56 字数 2582 浏览 8 评论 0原文

我正在使用 abcPdf 将 HTML 报告转换为 pdf 文件。 pdf 必须是单个横向 A4 页面。

您知道是否有任何方法可以告诉 abcPdf 缩放 HTML 页面以适合 pdf 中的单个页面?我尝试使用 Magnify() 方法,它会缩放内容,但仍然将其分成页面,即使它适合一页。我对此已经摸不着头脑有一段时间了,想知道是否有人做到了。

这是我目前使用的代码:

public byte[] UrlToPdf(string url, PageOrientation po)
{
    using (Doc theDoc = new Doc())
    {
        // When in landscape mode:
        // We use two transforms to apply a generic 90 degree rotation around
        // the center of the document and rotate the drawing rectangle by the same amount.
        if (po == PageOrientation.Landscape)
        {
            // apply a rotation transform
            double w = theDoc.MediaBox.Width;
            double h = theDoc.MediaBox.Height;
            double l = theDoc.MediaBox.Left;
            double b = theDoc.MediaBox.Bottom;
            theDoc.Transform.Rotate(90, l, b);
            theDoc.Transform.Translate(w, 0);

            // rotate our rectangle
            theDoc.Rect.Width = h;
            theDoc.Rect.Height = w;

            // To change the default orientation of the document we need to apply a rotation to the root page object.
            //By doing this we ensure that every page in the document is viewed rotated.
            int theDocID = Convert.ToInt32(theDoc.GetInfo(theDoc.Root, "Pages"));
            theDoc.SetInfo(theDocID, "/Rotate", "90");
        }

        theDoc.HtmlOptions.PageCacheEnabled = false;
        theDoc.HtmlOptions.AddForms = false;
        theDoc.HtmlOptions.AddLinks = false;
        theDoc.HtmlOptions.AddMovies = false;
        theDoc.HtmlOptions.FontEmbed = false;
        theDoc.HtmlOptions.UseResync = false;
        theDoc.HtmlOptions.UseVideo = false;
        theDoc.HtmlOptions.UseScript = false;
        theDoc.HtmlOptions.HideBackground = false;
        theDoc.HtmlOptions.Timeout = 60000;
        theDoc.HtmlOptions.BrowserWidth = 0;
        theDoc.HtmlOptions.ImageQuality = 101;

        // Add url to document.
        int theID = theDoc.AddImageUrl(url, true, 0, true);
        while (true)
        {
            if (!theDoc.Chainable(theID))
                break;
            theDoc.Page = theDoc.AddPage();
            theID = theDoc.AddImageToChain(theID);
        }
        //Flattening the pages (Whatever that means)
        for (int i = 1; i <= theDoc.PageCount; i++)
        {
            theDoc.PageNumber = i;
            theDoc.Flatten();
        }

        return theDoc.GetData();
    }
}

I am using abcPdf to convert an HTML report into a pdf file. The pdf has to be a single landscape A4 page.

Do you know if there is any way to tell abcPdf to scale the HTML page to fit on a single page in the pdf? I tried using the Magnify() method, and it scales the content but still breaks it into pages, even though it would fit on one page. I've been scratching my head on this for a while now, and am wondering if anyone has done it.

Here's the code I'm using at the moment:

public byte[] UrlToPdf(string url, PageOrientation po)
{
    using (Doc theDoc = new Doc())
    {
        // When in landscape mode:
        // We use two transforms to apply a generic 90 degree rotation around
        // the center of the document and rotate the drawing rectangle by the same amount.
        if (po == PageOrientation.Landscape)
        {
            // apply a rotation transform
            double w = theDoc.MediaBox.Width;
            double h = theDoc.MediaBox.Height;
            double l = theDoc.MediaBox.Left;
            double b = theDoc.MediaBox.Bottom;
            theDoc.Transform.Rotate(90, l, b);
            theDoc.Transform.Translate(w, 0);

            // rotate our rectangle
            theDoc.Rect.Width = h;
            theDoc.Rect.Height = w;

            // To change the default orientation of the document we need to apply a rotation to the root page object.
            //By doing this we ensure that every page in the document is viewed rotated.
            int theDocID = Convert.ToInt32(theDoc.GetInfo(theDoc.Root, "Pages"));
            theDoc.SetInfo(theDocID, "/Rotate", "90");
        }

        theDoc.HtmlOptions.PageCacheEnabled = false;
        theDoc.HtmlOptions.AddForms = false;
        theDoc.HtmlOptions.AddLinks = false;
        theDoc.HtmlOptions.AddMovies = false;
        theDoc.HtmlOptions.FontEmbed = false;
        theDoc.HtmlOptions.UseResync = false;
        theDoc.HtmlOptions.UseVideo = false;
        theDoc.HtmlOptions.UseScript = false;
        theDoc.HtmlOptions.HideBackground = false;
        theDoc.HtmlOptions.Timeout = 60000;
        theDoc.HtmlOptions.BrowserWidth = 0;
        theDoc.HtmlOptions.ImageQuality = 101;

        // Add url to document.
        int theID = theDoc.AddImageUrl(url, true, 0, true);
        while (true)
        {
            if (!theDoc.Chainable(theID))
                break;
            theDoc.Page = theDoc.AddPage();
            theID = theDoc.AddImageToChain(theID);
        }
        //Flattening the pages (Whatever that means)
        for (int i = 1; i <= theDoc.PageCount; i++)
        {
            theDoc.PageNumber = i;
            theDoc.Flatten();
        }

        return theDoc.GetData();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无法言说的痛 2024-08-26 02:30:56

这就是我解决这个问题的方法。

首先,我需要将 HTML 页面的高度传递给 pdf 生成方法,因此我在要进行 pdf 编辑的页面上添加了以下内容:

<asp:HiddenField ID="hfHeight" runat="server" />

在后面的代码中:

protected void Page_Init(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string scriptKey = "WidhtHeightForPdf";
        if (!Page.ClientScript.IsClientScriptBlockRegistered(scriptKey))
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script>")
                .AppendLine("document.getElementById('" + hfHeight.ClientID + "').value = document.body.clientHeight;")
                .AppendLine("</script>");

            Page.ClientScript.RegisterStartupScript(typeof(Page), scriptKey, sb.ToString());
        }
    }
}

现在,当我调用 pdf 生成方法时,我可以将 HTML 的高度传递给它。一旦我有了高度,就只需计算 pdf“视口”的宽度,使高度适合 pdf 页面:

int intHTMLWidth = height.Value * Convert.ToInt32(theDoc.Rect.Width / theDoc.Rect.Height);

然后通过 theDoc 的 HtmlOptions 指定 BrowserWidth 参数

theDoc.HtmlOptions.BrowserWidth = intHTMLWidth;

或者将网址添加到 theDoc 时:

int theID = theDoc.AddImageUrl(url, true, intHTMLWidth, true);

编辑:这解决了问题,所以我将其标记为答案。现在接下来要做的就是根据 HTML 的宽度和高度以纵向或横向模式创建 pdf,以便在 pdf 页面上使用最大空间。

So here's how I solved this.

First of all, I needed the height of the HTML page to be passed to the pdf generating method, so I added this on the page to be pdf-ed:

<asp:HiddenField ID="hfHeight" runat="server" />

and in the code behind:

protected void Page_Init(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string scriptKey = "WidhtHeightForPdf";
        if (!Page.ClientScript.IsClientScriptBlockRegistered(scriptKey))
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<script>")
                .AppendLine("document.getElementById('" + hfHeight.ClientID + "').value = document.body.clientHeight;")
                .AppendLine("</script>");

            Page.ClientScript.RegisterStartupScript(typeof(Page), scriptKey, sb.ToString());
        }
    }
}

Now, when I call the pdf generating method I can pass it the height of the HTML. Once I have the height it's all a matter of calculating the width of the pdf "viewport" such that the height fits on the pdf page:

int intHTMLWidth = height.Value * Convert.ToInt32(theDoc.Rect.Width / theDoc.Rect.Height);

And then specify the BrowserWidth parameter either through HtmlOptions of theDoc:

theDoc.HtmlOptions.BrowserWidth = intHTMLWidth;

or when adding the url to theDoc:

int theID = theDoc.AddImageUrl(url, true, intHTMLWidth, true);

EDIT: This solves the question, so I'm going to mark it as an answer. Now the next thing to do is create the pdf in protrait or landscape mode based on the width and height of the HTML, so that maximum space is used on the pdf page.

一身骄傲 2024-08-26 02:30:56

这可能会更简单一些

    /// <summary>
    /// Calculate the height of given html
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    public int CalculateHeight(string html)
    {
        int id = _Document.AddImageHtml(html);
        int height = (int)(_Document.GetInfoInt(id, "ScrollHeight") * PixelToPointScale);
        _Document.Delete( id );
        return height;
    }

[编辑]
好吧,scrollHeight 在 ver8 上失败了,但这可以工作

    private int AddImageHtml(string html)
    {
        try
        {
            return _Document.AddImageHtml("<div id='pdfx-div-pdf-frame' class='abcpdf-tag-visible' style='abcpdf-tag-visible: true; border: 1px solid red'>" + html + "</div>");
        }
        catch (Exception ex)
        {
            throw new Exception(html, ex);
        }
    }

    private double GetElementHeight(int id)
    {
        abcpdf.XRect[] tagRects = _Document.HtmlOptions.GetTagRects(id);
        string[] tagIds = _Document.HtmlOptions.GetTagIDs(id);

        for (int i=0;i<tagRects.Length;i++)
        {
            abcpdf.XRect rect = tagRects[i];
            string tagId = tagIds[i];
            if (string.Equals(tagId, "pdfx-div-pdf-frame", StringComparison.CurrentCultureIgnoreCase))
            {
                return rect.Height;
            }
        }
        return -1;
    }

This might be a bit simpler

    /// <summary>
    /// Calculate the height of given html
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    public int CalculateHeight(string html)
    {
        int id = _Document.AddImageHtml(html);
        int height = (int)(_Document.GetInfoInt(id, "ScrollHeight") * PixelToPointScale);
        _Document.Delete( id );
        return height;
    }

[edit]
Well scrollHeight fails with ver8 this works though

    private int AddImageHtml(string html)
    {
        try
        {
            return _Document.AddImageHtml("<div id='pdfx-div-pdf-frame' class='abcpdf-tag-visible' style='abcpdf-tag-visible: true; border: 1px solid red'>" + html + "</div>");
        }
        catch (Exception ex)
        {
            throw new Exception(html, ex);
        }
    }

    private double GetElementHeight(int id)
    {
        abcpdf.XRect[] tagRects = _Document.HtmlOptions.GetTagRects(id);
        string[] tagIds = _Document.HtmlOptions.GetTagIDs(id);

        for (int i=0;i<tagRects.Length;i++)
        {
            abcpdf.XRect rect = tagRects[i];
            string tagId = tagIds[i];
            if (string.Equals(tagId, "pdfx-div-pdf-frame", StringComparison.CurrentCultureIgnoreCase))
            {
                return rect.Height;
            }
        }
        return -1;
    }
纸短情长 2024-08-26 02:30:56

如果您使用“Gecko”引擎,该引擎不支持“GetInfoInt”,因此我们需要编写一些 JavaScript 来获取高度。首先进行虚拟渲染以确定高度,然后将此高度设置为原始 AbcDoc。

using (var tempDoc = new Doc())
                {
                    tempDoc.HtmlOptions.Engine = EngineType.Gecko;
                    tempDoc.HtmlOptions.Media = MediaType.Print;
                    tempDoc.HtmlOptions.UseScript = true;
                    if (width.HasValue)
                        tempDoc.HtmlOptions.BrowserWidth = width.Value;

                    tempDoc.HtmlOptions.OnLoadScript = " window.onbeforeprint = function () { document.documentElement.abcpdf = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight );}";
                    int theTempID = tempDoc.AddImageHtml(htmlData);

                    int height = Convert.ToInt32(tempDoc.HtmlOptions.GetScriptReturn(theTempID));

                    tempDoc.Clear();
                    tempDoc.Dispose();

                    theDoc.MediaBox.Height = height;
                    theDoc.Rect.String = theDoc.MediaBox.String;
                    theDoc.AddImageHtml(htmlData);
                }

In case you are using 'Gecko' engine, this engine does not support 'GetInfoInt' so we need write some javascript to get the height. Do a dummy render first to determine height and then set this height to original AbcDoc.

using (var tempDoc = new Doc())
                {
                    tempDoc.HtmlOptions.Engine = EngineType.Gecko;
                    tempDoc.HtmlOptions.Media = MediaType.Print;
                    tempDoc.HtmlOptions.UseScript = true;
                    if (width.HasValue)
                        tempDoc.HtmlOptions.BrowserWidth = width.Value;

                    tempDoc.HtmlOptions.OnLoadScript = " window.onbeforeprint = function () { document.documentElement.abcpdf = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight );}";
                    int theTempID = tempDoc.AddImageHtml(htmlData);

                    int height = Convert.ToInt32(tempDoc.HtmlOptions.GetScriptReturn(theTempID));

                    tempDoc.Clear();
                    tempDoc.Dispose();

                    theDoc.MediaBox.Height = height;
                    theDoc.Rect.String = theDoc.MediaBox.String;
                    theDoc.AddImageHtml(htmlData);
                }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文