Скажите abcPdf для масштабирования HTML, чтобы поместиться на одной странице PDF - PullRequest
5 голосов
/ 25 января 2010

Я использую abcPdf для преобразования отчета в формате HTML в файл PDF. PDF должен быть одной страницей формата А4.

Знаете ли вы, есть ли способ сказать 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();
    }
}

Ответы [ 3 ]

5 голосов
/ 26 января 2010

Так вот как я решил это.

Прежде всего, мне нужно было передать высоту HTML-страницы методу генерации pdf, поэтому я добавил ее на страницу, которая будет pdf-ed:

<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);

А затем укажите параметр BrowserWidth либо через HtmlOptions из theDoc:

theDoc.HtmlOptions.BrowserWidth = intHTMLWidth;

или при добавлении URL к theDoc:

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

РЕДАКТИРОВАТЬ: Это решает вопрос, поэтому я собираюсь пометить его как ответ. Теперь следующее, что нужно сделать, это создать pdf в режиме protrait или альбомной ориентации на основе ширины и высоты HTML-кода, чтобы на странице pdf использовалось максимальное пространство.

1 голос
/ 01 мая 2012

Это может быть немного проще

    /// <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;
    }
0 голосов
/ 04 марта 2015

В случае, если вы используете движок '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);
                }
...