dompdf icon indicating copy to clipboard operation
dompdf copied to clipboard

Scaling moves content and doesn't change page count

Open wardjk opened this issue 9 years ago • 11 comments

My objective is to create a PDF of an html table containing user-defined content that affects both the number of columns and rows in the table. For a selected paper size, the number of columns may cause the content to extend beyond the width of the page. I implemented a user-defined scale that effectively inserts body {-webkit-transform: scale(0.80);} as a style if the user sets the scale to 80%. This has the effect of reducing the height and width of the table to 80% but two undesired side effects occur:

  1. The left margin width is inversely proportional to the scale. The lower the scale, the greater the left margin width resulting in the right of the table still extending beyond the page width. This seems to be caused by the pdf content centered on the page even though the html page is aligned left. I've experimented with margins for html, body, and @page but these cause other undesired side effects.
  2. The number of table rows per page isn't increased when the content is scaled down resulting in the same number of pages consumed and content having greater top and bottom margins.

Is there a solution for reducing the scale of the content but keeping a consistent margin on all sides of the content regardless of scale?

wardjk avatar May 09 '16 16:05 wardjk

@wardjk yes, there is, but not with stock dompdf.

I patched dompdf to allow this and it's working fine for several years now :) With this patch you can even scale the content to fit on one single page.

It basically renders the pdf twice. In the first step it collects the maximum draw position in the canvas class and in the second step it renders the PDF using this new values as the paper size (using $dompdf->set_paper()).

I can provide you with the details/code, if you want :)

tmolitor-stud-tu avatar May 13 '16 13:05 tmolitor-stud-tu

Great. I'm guessing that as it is now, dompdf first decides the content for each page then performs the scaling rather than the other way around in which case it's a good thing my users are not likely scale up instead which would cause the content to exceed both the page width and height.

How can I get your solution?

wardjk avatar May 13 '16 16:05 wardjk

@wardjk you are correct, scaling occurs after the page layout is complete. But more importantly scaling only affect the visual appearance of the element, not it's layout on the page.

From the W3C Transform spec:

Note: Transformations do affect the visual layout on the canvas, but have no affect on the CSS layout itself.

bsweeney avatar May 13 '16 16:05 bsweeney

@wardjk I'll create a github project for this :) I think this would be the simplest solution. And maybe we even can get some of this changes upstream :)

tmolitor-stud-tu avatar May 15 '16 19:05 tmolitor-stud-tu

@wardjk done. You can get it here: https://github.com/tmolitor-stud-tu/dompdf/tree/0.6.2-scaling See render_scaled_pdf.php for an example using this patched version. If you have any questions: feel free to ask :)

tmolitor-stud-tu avatar May 15 '16 19:05 tmolitor-stud-tu

@wardjk did you test my solution?

tmolitor-stud-tu avatar Jun 16 '16 15:06 tmolitor-stud-tu

I just returned to this project to try your solution. Thanks for making it available. After replacing dompdf-0.6.2 with dompdf-0.6.2-scaling, I also copied dompdf/lib/php-font-lib from dompdf-0.6.2 which was trivial.

Upon running $dompdf->render(), I encountered Undefined offset: 1 ...dompdf\include\cpdf_adapter.cls.php(279)

276   protected function _update_yscaleflags($args=array())
277   {
278     foreach($args as $entry)
279         $this->_yscaleflag[$this->_page_number]=max($this->_yscaleflag[$this->_page_number], $this->y($entry));
280   }

Stack Trace cpdf_adapter.cls.php(635): 635 $this->_update_yscaleflags(array($y)); page_frame_reflower.cls.php(130): 130 $this->_frame->get_renderer()->render($child);

While debugging, I only got as far as discovering that the $_yscaleflag array is empty and the $args array contains one float value. I haven't investigated further.

wardjk avatar Jun 17 '16 14:06 wardjk

Well, that seems to be a php notice. In my environment notices are turned off via error_reporting(). If you don't want to turn off notices, you can just use this: $this->_yscaleflag[$this->_page_number]=max(isset($this->_yscaleflag[$this->_page_number]) ? $this->_yscaleflag[$this->_page_number] : 0, $this->y($entry));

tmolitor-stud-tu avatar Jun 17 '16 14:06 tmolitor-stud-tu

I added your suggestion which eliminated the problem.

My scaling test using dompdf-0.6.2-scaling didn't produce the desired results. At 100% scaling, my test table requires 3 pages. At 50% scaling, 3 pages are still consumed and the number of rows per page is the same even though the page contents are scaled down. This is the same result as with dompdf-0.6.2.

wardjk avatar Jun 17 '16 16:06 wardjk

@wardjk What html did you try to scale? And how did you invoke my code?

My changes only make it possible to have everything on one page or everything on multiple pages (always ensuring the content is not overflowing the right edge of a page).

If you want to do continous scaling by percent values, my approach isn't what you need (but it could be changed to allow percent scaling as well, I think).

tmolitor-stud-tu avatar Jun 18 '16 12:06 tmolitor-stud-tu

Just noting, an appropriate modification to Dompdf to support this would be to implement the zoom CSS property.

bsweeney avatar Jul 19 '25 18:07 bsweeney