wkhtmltopdf의 테이블 행 내부에서 페이지 나누기를 방지하는 방법


81

하나의 테이블이있는 html 페이지에서 pdf 보고서를 생성하고 있습니다.

나는 목적으로 wkhtmltopdf 를 사용하고 있습니다.

pdf가 생성되면 tr 태그의 어느 곳에서나 중단 됩니다.

나는 그것을 피하고 싶다.

답변:


152

업데이트 17.09.2015 : 사용중인 버전을 확인하십시오. wkhtmltopdf 0.12.2.4가 문제를 해결한다고합니다 (확인하지 않았습니다) .


이것은 wkhtmltopdf의 알려진 문제입니다. 웹킷 (WKhtmltopdf의 WK)에서 사용하는 페이지 나누기 알고리즘은 실제로 큰 테이블에서 제대로 작동하지 않습니다. 테이블을 페이지로 더 쉽게 분할하고 CSS를 많이 사용하는 작은 청크로 분할하는 것이 좋습니다.

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

또한 다음 wkhtmltopdf 문제를 살펴보십시오. 예를 들어 테이블 분할 문제를 논의하는 흥미로운 주석이 있습니다. 도움이 될 수있는 168 테이블을 프로그래밍 방식으로 분할하는 JS 솔루션이 있습니다 (하지만 사용하지는 않습니다).

업데이트 08.11.2013 위에 링크 된 168 ​​호에서 이에 대한 많은 논의가 있습니다. 누군가가 더 나은 테이블 분할을 지원하는 wkhtmltopdf 버전을 컴파일했지만 안타깝게도 공식적으로 릴리스되지 않았으며 다른 버그가 포함될 수 있습니다. 나는 그것을 얻는 방법을 모르고 Windows에서 컴파일하는 방법을 모르지만 관심있는 사람은 여기 에서 주석을 확인할 수 있습니다 (아래의 새 업데이트 참조).

업데이트 24.02.2014 wkhtmltopdf 0.12에서이 기능이 크게 개선되었다는 소식을 듣고 기뻐하실 것입니다. 그러나 새 버전을 사용하기 전에 0.12.1을 기다렸다가 철저히 테스트하십시오. 안티 알 리즈로 작업하는 새 직원이 훌륭한 작업을 수행하고 있지만 (ashkulz 바위) 여전히 약간 불안정합니다! wkhtmltopdf.orggithub 에서 계속 업데이트하십시오 . Google 코드 사이트는 더 이상 사용되지 않으며 천천히 마이그레이션됩니다.


1
정보 주셔서 감사합니다. 버전 0.12.1은 페이지 나누기 문제를 해결합니다.
Nidhi Sarvaiya 2014

1
이 솔루션은 최신 0.12.1 버전에서만 작동합니다. 이전 항목은 여전히 ​​작동하지 않습니다.
Cerin 2014

4
나는 이틀 동안 이것으로 고생했다. 내 테이블은 스타일이 display: inline-block. 로 변경하고 block위의 변경 사항이 모두 작동하기 시작했습니다!
Hugh

2
@Nenotlep 귀하의 답변에 감사드립니다. 네, 이미 이것에 대한 새로운 질문을 올렸습니다 : stackoverflow.com/q/36334330/3391783- 이 모든 것이 0.12.1-ish 또는 0.12.2-ish 버전에서 다시 작동하는 것처럼 보였고 0.12에서 다시 깨졌습니다. 3-ish 버전.
low_rents

2
@DjDacSaunders WKHTMLTOPDF는 순수한 html-> pdf 도구가 아닌 해킹입니다. 요점은 매우 긴 문서를 페이지 형식으로 렌더링하는 것입니다. 우리가 이것을 통제 할 수 있다는 사실은 훌륭합니다. 이것이 가장 좋은 접촉 장소를 개선하기를 원한다면 QT 프로젝트 또는 아마도 WebKit 프로젝트 인 wkhtml의 업스트림입니다. 웹 페이지를 PDF 파일로 렌더링 할 때 WebKit이 의도 한 것이 아니기 때문에이 일이 결코 변하지 않을 것으로 예상합니다. : / 완전한 제어를 위해 PrinceXML을 사용해보십시오. (x) HTML은 인쇄 형식이 아니며 그 문제에 대한 "솔루션"은 항상 해킹입니다.
Joel Peltonen 17.10.20

18

오래된 게시물이지만 적절한 해결책을 찾으려고 많은 시간을 낭비했기 때문에 여기에 넣을 것입니다. 아마도 누군가에게 유용 할 것입니다.

그래서 내가 읽은 것에서 문제는

page-break-inside: avoid

작동하지 않는다는 것입니다. 그러나 실제로 display:block예상대로 작동 하는 요소에 설정하면 (SO 어딘가에서 언급했듯이). 그래서 테이블 css의 간단한 구조를 위해

td div, th div{
    page-break-inside: avoid;
}

및 테이블 구조

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

예상대로 작동합니다.

행 범위에 대해 좀 더 복잡한 경우가 있었기 때문에 위의 솔루션은 원하는 효과가 아닌 평화를 깨뜨리는 것이 었습니다. 나는 각 행에 걸친 행 세트에 대해 div를 사용하여 해결했습니다. 내 jquery js는 모든 작업을 수행합니다.

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

CSS :

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

모든 것이 필요한지 모르겠고 완벽하다고 생각하지는 않지만 일을합니다. 크롬에서만 테스트


16

0.12부터이 문제가 해결되었지만 때로는 표가 너무 길어서 페이지에 맞지 않는 경우 wkhtmltopdf가 표를 두 부분으로 나누고 새 페이지의 열 머리글을 반복하며 이러한 열 머리글은 첫 번째 행에 겹쳐서 나타납니다.

wkhtmltopdf github 문제 섹션에서이 문제에 대한 일시적인 해결책을 찾았습니다 : https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

뷰 CSS에 다음 줄을 추가하십시오.

tr {
  page-break-inside: avoid; 
}

이것은 실제로 도움이됩니다. 감사합니다!! 이것이 기본 동작이 아닌 이유를 모르겠습니다.
JosephK

6

나는 며칠 동안이 문제를 파헤 쳤고 마침내 완벽한 해결책을 찾았습니다. 이 프로젝트 phpwkhtmltopdf를 참조 할 수 있습니다 . 디렉토리를 살펴보면 article3 가지 문제에 대한 3 가지 해결책을 찾을 수 있습니다. 요컨대, 궁극적 인 해결책은 CSS 스타일을 추가하는 것입니다.

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

당신이있는 거 중국어,이 사이트에 확인해 주시기 바랍니다 경우关于wkhtmltopdf을你一定想知道这些 원하는 경우 요점을 확인 wkhtmltopdf에 대한 요점을


이것은 나를 위해 일했습니다. wkhtmltopdf 0.12.4를 사용 하고 있습니다 . 감사!
Hugo

5

wkhtmltopdf 0.12.2.1 이상으로이 문제가 해결되었음을 알았습니다.


7
그건 사실이 아니야. 여전히 문제가 있습니다.
Niklas R.

1
그리고 이것은 단지 주석이어야합니다.
Wesley Brian Lachenal

5

내 특별한 경우 어떤 이유로 이전 답변 중 어느 것도 나를 위해 일하지 않았습니다. 결국 작동하게 된 것은 실제로 여러 가지의 조합이었습니다.

  1. pip3을 사용하여 pdfkit 이라는 Wkhtmltopdf 파이썬 래퍼를 설치했습니다 (Ubuntu 16.04에서) , apt-get을 통해 Wkhtmltopdf를 설치하는 대신 여기 에서 가져온 아래 스크립트에 따라 정적 바이너리 (버전 0.12.3)를 설치했습니다 .

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. 이 CSS를 추가했습니다 (여기 답변 중 하나에서 제 안됨).

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. 그런 다음 여기에 제안 된대로 및 태그 추가 합니다 (이들 없이도 테이블은 추악한 방식으로 깨질 것입니다).<thead><tbody>

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

이러한 수정을 통해 이제 Mako 템플릿 을 성공적으로 사용 하여 HTML을 생성 한 다음 Wkhtmltopdf에 피드하고 아름다운 페이지가 매겨진 PDF를 얻을 수 있습니다.


4

테이블에 대한 모든 조작을 시도했지만 페이지 나누기가 행 중간에 들어가는 것을 막을 수있는 방법은 없습니다. 필사적으로 다른 버전을 시도해 보았고 다음을 발견했습니다.

Wkhtmltopdf 0.12.2.1 : 나쁨

Wkhtmltopdf 0.12.3 : 나쁨

Wkhtmltopdf 0.12.1 : 좋음

내 해결책은 버전 0.12.1로 다운 그레이드하는 것이 었는데, 이로 인해 문제가 해결되었습니다. 물론, 그것들은 부분적으로 내 html에 대한 강박증이 아니었기 때문일 수도 있지만 HTML이 TinyMCE (사용자에 의해) 내부에서 생성되기 때문에 선택의 여지가별로 없습니다.

또한 중첩 테이블은 어떤 버전에서도 작동하지 않습니다.


나를 위해 0.12.1은 문제를 해결하지 못하며, 제거해야합니다
UnixAgain dec

2

tr을 끊지 않고 pdf 내에서 페이지 나누기를 사용하는 방법은 무엇입니까?

다음은 모든 html 파일에서 사용할 수있는 솔루션입니다 .....

tr을 시작한 후에는 tr 내부에서 div를 가져 와서이 CSS를 div에 제공해야합니다.

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>

2

나는이 CSS가 문제를 해결 한 많은 시도 n 오류 후에 동일한 문제에 직면했습니다.

tr {
    display: inline-table;
}


1

위의 답변은 저에게 효과가 없었습니다. 내 pdfkit 구성 확대 / 축소 옵션을 특별히 비활성화해야했습니다.

PDFKit.configure do |config|

  config.default_options = {
    print_media_type: false,
    page_size: "A4",
    encoding: "UTF-8",
    ## Make sure the zoom option is not enabled!
    ## zoom: '1.3',
    disable_smart_shrinking: false,
    footer_right: "Page [page] of [toPage]"
  }

end

1

여전히 이것에 문제가있는 사람을 위해 기억해야 할 것은 테이블body 의 직접적인 자식 이어야한다는 것입니다. 그렇지 않으면 CSS가 작동하지 않을 것입니다 (적어도 나에게 일어난 일입니다).


이 나를 위해이 아니었다 - 나는 심지어 중첩 된 테이블이 페이지 나누기를 존중 확인할 수있다 ... 나를 위해 문제는 우분투 대 더 맥 OS는 ...이었다
페트로프

비슷한 문제가 발생했습니다. 내 테이블이 display: table-cell;적용된 div 내에있었습니다 . 이러한 스타일로 @media only screen페이지 나누기를 수정했습니다. 페이지 나누기가 작동하지 않으면 CSS의 절반을 단계적으로 제거하고 작동하는지 확인하여 나누고 정복하십시오.
Leslie Viljoen

1

이 말도 안되는 해결책을 찾았지만 잘 작동했습니다. 나를 :)

이렇게 매우 긴 행 범위 열을 넣었습니다.

<td rowspan="XXX TOTAL ROWS" style="width:0px"></td>

그러면 테이블이 깨지지 않습니다.


1

또 다른 옵션 : 각각 tr을 배치 tbody한 다음 peage break css 규칙을 tbody. 테이블은 여러tbody .

약간의 추가 마크 업이 있지만 괜찮습니다.


특정 행 그룹을 함께 유지하기 위해 별도의 tbody 요소 내에 배치하는 tr 요소 그룹에서 이것을 시도했습니다. 효과가 없었습니다. "page-break-inside : avoid;"없이이 방법을 수행합니다. "tr"요소에서 다시 페이지 머리글 위에 데이터를 인쇄하도록 복귀했습니다 ( "기본"동작).
JosephK

예, 이제 tbody와 tr 및 td 모두에 동일한 "page-break-inside : avoid"규칙을 적용합니다. "tbody, tbody> tr, tbody> tr> td, tbody> tr> th {page-break-inside : avoid;} "는 대부분의 상황에서 작동하는 것으로 보입니다.
Troy Morehouse 2017 년

고마워요.하지만 그냥 해봤어요. 내 tbody 그룹의 테이블 행 중간에서 여전히 페이지 나누기. 나는 또한 tbody에 클래스를 추가하고 'avoid'로 클래스에 CSS를 추가하려고 시도했습니다. 나는 이것이 css-rule로 실제로 "하는 일"이 무엇인지 알았 으면 좋겠다-아마도 trs 그룹이 실제로 '한 행'이라고 생각하게 만드는 방법-하지만 tr 2x +를 높이면 그것을 깨뜨리기 때문에 나는 추측하고있다 아니. 아마도 누군가는 10 년 후에 사용 가능한 HTML to PDF 솔루션을 만들 것이지만, 대신 직접적인 신경 데이터 전송을 기다리고 있다고 생각합니다.
JosephK

1

몇 가지 제안 된 솔루션을 조합하여 문제를 해결했습니다.

내 테이블을 div에 래핑하고 다음 CSS를 정의했습니다.

.wrapping-div {
        display: block;
        page-break-inside: avoid !important;
    }

.wrapping-div table, .wrapping-div tbody, .wrapping-div tr, .wrapping-div td, .wrapping-div th {
        page-break-inside: avoid !important;
    }

완료시 테이블 구조는 다음 예와 같이 정의되었습니다.

<div class="wrapping-div">
 <table>
  <tbody>
   <tr>
    <th>
      header
    </th>
    <td>
      content
    </td>
   </tr>
  </tbody>
 </table>
</div>

td 또는 th 태그 안에 div를 만들 필요가 없었습니다.

문제를 해결하는 동안 알아 차린 중요한 사항 :

  • tbody는 테이블에 포함되어야합니다.
  • div에는 display : block이 있어야합니다.
  • 표가 한 페이지에 맞지 않으면 자동으로 전체 표를 다음 페이지로 이동합니다 (큰 표로이 표를 시도하지 않았습니다).
  • CSS에서 ".wrapping-div table" 선택기 만 제거 하면 표가 두 페이지로 분할 될 수 있지만 올바르게 렌더링되고 두 페이지에서 한 셀이 분할되지 않습니다 (Word의 기본 동작과 유사). )

이게 도움이 되길 바란다.



1

페이지 나누기를 방지하기 위해 페이지 나누기 css 방지 옵션을 사용할 수 있습니다.

tr { page-break-inside: avoid; }

콘텐츠 (이미지 / 텍스트) 를 나누고 다음 페이지에 표시되도록합니다 .

.sample-image { page-break-before: always; }

0

테이블 헤드가 있습니까? 그리고 테이블 본체?

<table>
<tbody>
<tr><th>Name</th><th>Value</th></tr>
<tr><td>url</td><td>stackoverflow.com</td></tr>
<tr><td>ip</td><td>123.123.123.123</td></tr>
</tbody>
</table>

그것은 표의 적절한 형식입니다. 대부분의 브라우저 는 그다지 신경 쓰지 않지만, 언급 한 것과 같은 변환기 는 누락 된 태그 <tbody><th>태그를 먼저 추가 할 것을 제안합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.