Welcome Guest Search | Active Topics | Sign In | Register

Different margins on different pages Options
Megan
Posted: Wednesday, September 11, 2019 12:14:12 PM
Rank: Newbie
Groups: Member

Joined: 9/11/2019
Posts: 4
We have a scenario where we need to have different margins on the first and last pages (left/right and top/bottom). Content is user-generated, varies in length, and while users can specify page breaks, they are not required. For the most part, we just have a chunk of HTML with no defined page breaks and rely on the automatic paging.

The scenario is that sometimes users want 0 margins on the first or last page, so they can do something like a full page image, but normal margins everywhere else.

From reading other forum posts and documentation, I am aware there cannot be more than 1 OutputArea defined for each call to ConvertHtml(). I am aware that if you know ahead of time where page breaks are and you know which HTML goes on which page, you can call ConvertHtml() multiple times for each unique OutputArea like this (taken from your reply to another forum post):

Code: C#
PdfDocument doc = new PdfDocument();

HtmlToPdf.Options.OutputArea = ...
HtmlToPdf.ConvertHtml(html1, doc);

doc.Pages.Add();
HtmlToPdf.Options.OutputArea = ....
HtmlToPdf.Options.StartPageIndex = 1;
HtmlToPdf.ConvertHtml(html2, doc);



In the example there is html1 and html2. For us we just have one big chunk of HTML and rely on automatic paging. I'm unsure how to divide the HTML up per page, in a way that matches your automatic paging but with different sized OutputAreas on different pages.

I've read this:
https://www.essentialobjects.com/doc/pdf/htmltopdf/paging.aspx

And have tried using the Paginator class, but I am unclear how to use it with different OutputAreas.

I've tried doing something like the below, but clearly this is not the right way to approach it, as margins for the entire report just end up based on the last OutputArea I set (the one for the last page). I am guessing the rule that there cannot be multiple OutputAreas for each ConvertHtml() call applies to HtmlToPdfSession.RenderAsPDF() as well.

Code: C#
HtmlToPdfResult htmlToPdfResult;

var doc = new PdfDocument();


using (HtmlToPdfSession session = HtmlToPdfSession.Create(pdfOptions))
{
    session.LoadHtml(html);

    // set output area for first page
    session.Options.OutputArea = new RectangleF(firstPageLeft, firstPageTop, firstPageWidth, firstPageHeight);

    Paginator paginator = session.CreatePaginator();

    // set output area for middle pages
    session.Options.OutputArea = new RectangleF(left, top, width, height);

    paginator.Pages[1].PageAgain(paginator.FullPageHeight);

    // set output area for last page
    session.Options.OutputArea = new RectangleF(lastPageLeft, lastPageTop, lastPageWidth, lastPageHeight);
    paginator.Pages[paginator.Pages.Count - 1].PageAgain(paginator.FullPageHeight);

    htmlToPdfResult = session.RenderAsPDF(doc);
}



Any clues as to how to accomplish this would be appreciated.

Thanks!

(Edit: originally posted this in General Discussion by accident, moving it under Support.)
eo_support
Posted: Wednesday, September 11, 2019 2:06:54 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,103
Hi,

You will either have to use two separate ConvertHtml calls, or modify your HTML to implement the margins in your HTML.

The hard rule here is no matter what you do, one ConvertHtml can only have a single OutputArea.Width. This is true even if you use custom paging. This is because internally the HTML to PDF converter creates an off screen browser window, then load and render the HTML into that window. That window, just like a normal on screen browser window, can only have a single width value. You can not have a window on screen that is wider on the top half and narrower on the bottom half --- that can only be achieved by using two separate windows. The entire HTML layout engine is designed on the notion of having a fixed width and then flow the document vertically however long as needed. So a single width value for the entire conversion is an iron rule that can not be bent. Custom paging will not change this rule because paging deals with Y axis, not X axis.

If using separate ConvertHtml calls is not an option for you, you can format your HTML into something like this:

Code: HTML/ASPX
<div>
    first page contents
</div>
<div style="padding-left: 10px; padding-right:10px;page-break-before:always">
    other contents that flow through multiple pages
</div>


You would then run ConvertHtml with the above HTML on full width with no margins. This way the first page contents will not have any margins. However contents in the second DIV will have whatever margins you specify on your second DIV. This way you are basically implementing the margins in your HTML.

The page-break-before:always on the second DIV is not required. For example, if your first DIV contents fits exactly the entire first page then the automatic paging process would push the second DIV to the second page even without this attribute. You can also use custom paging if more complex logic is required --- but remember paging is for Y axis, not for X axis.

Hope this helps. Please feel free to let us know if you still have any more questions.

Thanks!

Megan
Posted: Wednesday, September 11, 2019 5:41:34 PM
Rank: Newbie
Groups: Member

Joined: 9/11/2019
Posts: 4
Thanks for the feedback. I understand what you're saying about why each ConvertHtml call can have only one single OutputArea.Width. If I have this correct, you are saying there are 2 options:

1) Format our HTML and set margins in the HTML per page accordingly (your code example)

Unless I am missing something, this will not work as we don’t know where page breaks should be. There is no way to make a div for the first page contents like in your code sample, because we don’t know ahead of time what all will fit on the first page. Again, in our scenario this is user-generated content – it’s different every time. It could be HTML elements, text nodes that end up spanning multiple pages, etc. Page breaks are not defined ahead of time. We have one chunk of HTML and rely on the automatic paging to break it up into pages.


2) Make multiple ConvertHtml calls
Again, unless I am missing something, this is not going to work for our scenario. This is the same problem as above. How can I make multiple ConvertHtml calls if I don’t know what HTML is to be in each individual page?

Code: C#
PdfDocument doc = new PdfDocument();

HtmlToPdf.Options.OutputArea = ...
HtmlToPdf.ConvertHtml(html1, doc);

doc.Pages.Add();
HtmlToPdf.Options.OutputArea = ....
HtmlToPdf.Options.StartPageIndex = 1;
HtmlToPdf.ConvertHtml(html2, doc);

In this code sample, how do I know what html1 is and what html2 is? I only have one string of HTML with no page break designations.



It sounds to me like we cannot accomplish different margins for different pages, unless we know page breaks ahead of time (which we do not in our scenario). Can you please confirm I have that correct?

If that is the case, perhaps it means my company needs to require our users to explicitly define page breaks if they need pages with differing margins. If page breaks are explicitly defined, we should then be able to use one of your two suggestions above. Again, if you could please confirm I have the above correct, that would be super helpful. Thanks.
eo_support
Posted: Wednesday, September 11, 2019 6:42:42 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,103
Hi,

Yes. Your understanding is correct. Technically you do NOT have to require your customer to explicitly define page breaks. The information you need from your customer is if a piece of contents requires a different margin, then that contents need to be separated. In another word, if you have two different margins, you MUST have two separate HTML strings. This is because a single HTML string can only have a single margin settings.

Thanks!
Tyler Miller
Posted: Monday, October 17, 2022 5:01:41 PM
Rank: Advanced Member
Groups: Member

Joined: 1/22/2014
Posts: 38
eo_support wrote:
Hi,

Yes. Your understanding is correct. Technically you do NOT have to require your customer to explicitly define page breaks. The information you need from your customer is if a piece of contents requires a different margin, then that contents need to be separated. In another word, if you have two different margins, you MUST have two separate HTML strings. This is because a single HTML string can only have a single margin settings.

Thanks!


Searching for a way forward ... is there any way to do either of the following to have a custom bottom margin on the first page?

1. CSS?

@page:first {
margin-bottom: 4in;
}

2. Calculate the size of parts of the output when rendered?
eo_support
Posted: Tuesday, October 18, 2022 9:51:31 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,103
Hi Tyler,

#1 is not possible but #2 is. You can use a custom pager to "see" the size of each elements and then decide where to page yourself. See here for more details:

https://www.essentialobjects.com/doc/pdf/htmltopdf/paging.html#custom

To achieve a different bottom margin you only need to do something like this:

Code: C#
paginator.Pages[0].PageAgain(first_page_content_height);


This will break the first page at the height you set and then fill up all the remaining page based on your margin settings.

Hope this helps. Please feel free to let us know if you still have any more questions.

Thanks!

Tyler Miller
Posted: Tuesday, October 18, 2022 6:01:23 PM
Rank: Advanced Member
Groups: Member

Joined: 1/22/2014
Posts: 38
I'm using ConvertHtml. How would I paginate with that?
eo_support
Posted: Wednesday, October 19, 2022 8:52:55 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,103
Tyler Miller wrote:
I'm using ConvertHtml. How would I paginate with that?


You can no longer use HtmlToPdf.ConvertHtml directly when you use custom pager. You would need to follow the sample code in the above link that uses a HtmlToPdfSession object, but you would replace the LoadUrl call with LoadHtml instead.


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.