Skip to content

Commit

Permalink
Pdf Charts and Drawings
Browse files Browse the repository at this point in the history
Fix #4129. Fix #4168. Html Writer, which all the Pdf writers use, defines its charts and drawings (henceforth I will just use charts for this discussion) using position:absolute and z-index. Browsers handle this correctly, but none of the Pdf writers do, and I can't think of an alternative method of styling them. The result is that the charts take up too much or too little room on the Pdf.

I suggested in the two discussions that treating the areas covered by the charts as merged cells might mitigate the problem. I think there are too many unknowns to do so automatically (and see next paragraph). However, adding to Spreadsheet new methods `mergeChartCellsForPdf` and `mergeDrawingCellsForPdf` allows the end user to do this if desired. The new methods are exercised for charts in samples/Chart/32_Chart_read_write_PDF, the results of which are much improved as a result. New samples/Pdf/21f_Drawing_mpdf does likewise for drawings.

The new methods alter the spreadsheet they are working on, which could be a problem if you still wish to work with the spreadsheet after writing it to Pdf. In that case, making a copy of the spreadsheet, then calling the new methods on the copy, and writing the copy to Pdf is probably best.
  • Loading branch information
oleibman committed Jan 26, 2025
1 parent fb757cf commit 4a2b731
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
3 changes: 3 additions & 0 deletions samples/Chart/32_Chart_read_write_PDF.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($inputFileName);

$helper->log('Merge chart cells (needed only for Pdf)');
$spreadsheet->mergeChartCellsForPdf();

$helper->log('Iterate worksheets looking at the charts');
foreach ($spreadsheet->getWorksheetIterator() as $worksheet) {
$sheetName = $worksheet->getTitle();
Expand Down
50 changes: 50 additions & 0 deletions samples/Pdf/21f_Drawing_mpdf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf;

require __DIR__ . '/../Header.php';
require_once __DIR__ . '/Mpdf2.php';

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

$sheet->getCell('A1')->setValue('A1');
$sheet->getCell('B1')->setValue('B');
$sheet->getCell('C1')->setValue('C');
$sheet->getCell('D1')->setValue('D');
$sheet->getCell('E1')->setValue('E');
$sheet->getCell('F1')->setValue('F');
$sheet->getCell('G1')->setValue('G');
$sheet->getCell('A2')->setValue('A2');
$sheet->getCell('A3')->setValue('A3');
$sheet->getCell('A4')->setValue('A4');
$sheet->getCell('A5')->setValue('A5');
$sheet->getCell('A6')->setValue('A6');
$sheet->getCell('A7')->setValue('A7');
$sheet->getCell('A8')->setValue('A8');

$helper->log('Add drawing to worksheet');
$drawing = new Drawing();
$drawing->setName('Blue Square');
$path = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'images/blue_square.png';
$drawing->setPath($path);
$drawing->setResizeProportional(false);
$drawing->setWidth(320);
$drawing->setCoordinates('B2');
$drawing->setCoordinates2('G6');
$drawing->setWorksheet($sheet, true);

$helper->log('Merge drawing cells for Pdf');
$spreadsheet->mergeDrawingCellsForPdf();

$helper->log('Write to Mpdf');
$writer = new Mpdf($spreadsheet);
$filename = $helper->getFileName(__FILE__, 'pdf');
$writer->save($filename);
$helper->log("Saved $filename");
if (PHP_SAPI !== 'cli') {
echo '<a href="/download.php?type=pdf&name=' . basename($filename) . '">Download ' . basename($filename) . '</a><br />';
}
$spreadsheet->disconnectWorksheets();
48 changes: 48 additions & 0 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -1610,4 +1610,52 @@ public function setValueBinder(?IValueBinder $valueBinder): self

return $this;
}

/**
* All the PDF writers treat charts as if they occupy a single cell.
* This will be better most of the time.
* It is not needed for any other output type.
* It changes the contents of the spreadsheet, so you might
* be better off cloning the spreadsheet and then using
* this method on, and then writing, the clone.
*/
public function mergeChartCellsForPdf(): void
{
foreach ($this->workSheetCollection as $worksheet) {
foreach ($worksheet->getChartCollection() as $chart) {
$br = $chart->getBottomRightCell();
$tl = $chart->getTopLeftCell();
if ($br !== '' && $br !== $tl) {
if (!$worksheet->cellExists($br)) {
$worksheet->getCell($br)->setValue(' ');
}
$worksheet->mergeCells("$tl:$br");
}
}
}
}

/**
* All the PDF writers do better with drawings than charts.
* This will be better some of the time.
* It is not needed for any other output type.
* It changes the contents of the spreadsheet, so you might
* be better off cloning the spreadsheet and then using
* this method on, and then writing, the clone.
*/
public function mergeDrawingCellsForPdf(): void
{
foreach ($this->workSheetCollection as $worksheet) {
foreach ($worksheet->getDrawingCollection() as $drawing) {
$br = $drawing->getCoordinates2();
$tl = $drawing->getCoordinates();
if ($br !== '' && $br !== $tl) {
if (!$worksheet->cellExists($br)) {
$worksheet->getCell($br)->setValue(' ');
}
$worksheet->mergeCells("$tl:$br");
}
}
}
}
}

0 comments on commit 4a2b731

Please sign in to comment.