Kozea / WeasyPrint

The awesome document factory
https://weasyprint.org
BSD 3-Clause "New" or "Revised" License
7.14k stars 681 forks source link

counter-reset: page #93

Closed hejsan closed 5 years ago

hejsan commented 11 years ago

Is there a plan to support counter-reset?

I have to generate a pdf combined of a lot of reports for different students. Each report needs to have individual page numbers, i.e. not 1/117 thru 117/117 but instead each one would have numbers relative to just that one report, more like 1/5 thru 5/5 and so on.

So optimally counter-reset: page; should reset the counter to 1 and also make the counter(pages) evaluate correctly the number of pages since the last reset.

Is that even doable?

As a backup plan, do you know of any commandline tool to merge multiple pdf's into one that installs on centos?

Thanks for a superb tool btw.

SimonSapin commented 11 years ago

Hi. In this case I’d recommend using the low-level API to render multiple document separately, then write them to a single PDF file. Something like this:

documents = [HTML(string=render_template(student)).render() for student in students]
documents[0].copy([page for doc in documents for page in doc.pages]).write_pdf(target)
SimonSapin commented 11 years ago

Note: PDFtk can also concatenate PDF files, but that’s probably less efficient than the above as it’s just doing more work.

hejsan commented 11 years ago

Thanks. Yes I guess this is the only hack free way. I'm guessing if named pages were supported I could generate one @page for each student to allow for different headers and footers, but the page counter would still give me problems.

As this must be a common requirement, to generate multiple documents in a batch, is this a feature you'd be interested in having in weasyprint?

Thanks again. On 24 May 2013 05:00, "Simon Sapin" notifications@github.com wrote:

Note: PDFtk http://www.pdflabs.com/docs/pdftk-cli-examples/ can also concatenate PDF files, but that’s probably less efficient than the above as it’s just doing more work.

— Reply to this email directly or view it on GitHubhttps://github.com/Kozea/WeasyPrint/issues/93#issuecomment-18386661 .

SimonSapin commented 11 years ago

Even with named page, you’d still need more CSS features (like a new page selector) to only reset the page counter on the first page for a given student.

The low-level API (separating the layout into pages form the painting and PDF writing) was designed for this kind thing, and is already supported. What feature do you mean exactly?

hejsan commented 11 years ago

Hi, sorry to be unclear.

I may have misunderstood the css page standard (http://dev.w3.org/csswg/css-page/#page-based-counters)

I thought I could simply wrap each "subreport" like this:

<div class="student-report">
 ... report content ... 
</div>
<div class="student-report">
 ... report content ... 
</div>
...

and in the css I'd write:

@page {
    bottom-center {
        content: counter(page)/counter(pages);
    }
}
.student-report {
    counter-reset: page;
    page-break-after: always;
}

And this would have the effect that each student-report would have it's own page numbers and page count.

SimonSapin commented 11 years ago

I find the spec a bit unclear on this point, but I’m told that this wouldn’t work because of the scoping rules. Your explicit counter-reset would create one scope, and the implicit increment in @page would be a new scope, so that you actually have two page counters.

Maybe we should fix the spec to allow this use case.

ktross commented 9 years ago

I would love to see this supported in WeasyPrint. The only html to pdf renderer I have found that supports this is PrinceXML. Below is an example document that should have 5 total pages with 2 separate counters each having 3 and 2 total pages. Here is a pdf that I generated using the html below.

<!doctype html>
<html>
<head>
    <style>
    div.section {
        counter-reset:page 1 pages 1;
    }
    div.page {
        page-break-after:always;
    }
    @page {
        @top-center {
            content: "Page " counter(page) " of " counter(pages);
        }
    }
    </style>
</head>
<body>
    <div class="section">
        <div class="page">
            this should be page 1/3
        </div>
        <div class="page">
            this should be page 2/3
        </div>
        <div class="page">
            this should be page 3/3
        </div>
    </div>
    <div class="section">
        <div class="page">
            this should be page 1/2
        </div>
        <div class="page">
            this should be page 2/2
        </div>
    </div>
</body>
</html>
marine-dj commented 9 years ago

It would be really sweet if weasyprint could use counter-reset at all - so far I'm surprised to see just how much can actually be done, and this seems to be the only immediate drawback. :)

rpzk commented 8 years ago

Hello! Could you please clarity this code to me and point me to more productive direction? """ documents = [HTML(string=render_template(student)).render() for student in students] documents[0].copy([page for doc in documents for page in doc.pages]).write_pdf(target) """ Because I need to throw a pdf with several pages, with different orientations, backgrounds and sizes. This is a fragment of my code:

paginas = []
if orientacoes['orientacoes']:
    orientacoes_template = loader.get_template("impressos/receitas/orientacoes.html")
    orientacoes_html = orientacoes_template.render(RequestContext(request, dict(contexto.items() + orientacoes.items())))
    orientacoes_pdf = HTML(string=orientacoes_html).render()
    paginas.append(orientacoes_pdf)
if estadual['estadual']:
    estadual_template = loader.get_template("impressos/receitas/estadual.html")
    estadual_html = estadual_template.render(RequestContext(request, dict(contexto.items() + estadual.items())))
    estadual_pdf = HTML(string=estadual_html).render()
    paginas.append(estadual_pdf)
paginas[0].copy([pagina for p in paginas for pagina in p.pages]).write_pdf('teste.pdf')
return HttpResponse(paginas, content_type='application/pdf')

Thanks a lot for your knowledge and time.

Tontyna commented 6 years ago

The PrinceXML example provided by @ktross is desirable and plausible but doesn't conform to the spec. Quoting section 7.1:

Additionally, a counter named ‘pages’ is automatically created by the UA. Its value is always the total number of pages in the document. (In continuous media this is always 1.) The value of ‘pages’ cannot be manipulated: while ‘counter-reset’ and ‘counter-increment’ statements that set it are valid, they have no effect.

An immutable pages counter in combination with a changeable page counter? Sounds ill-conceived -- but that's what the spec says.

danfitz36 commented 6 years ago

named pages and custom counters would allow for separate page numbers per section, but is there a way to get the total pages per section?

liZe commented 5 years ago

An immutable pages counter in combination with a changeable page counter? Sounds ill-conceived -- but that's what the spec says.

Then we can close this issue. Reading #631 helps to understand how counters work according to the spec.

named pages and custom counters would allow for separate page numbers per section, but is there a way to get the total pages per section?

I've tried hard to find a solution for this, but I can't find it :cry:. It's more a limitation of the spec than a limitation of WeasyPrint as far as I can tell.