From 8a6142947eed7c18e8734edea03fa754a01e321d Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Sun, 23 Jul 2023 21:22:43 -0700 Subject: [PATCH] Minor Changes to Writer/Mpdf and Writer/Html (#3645) * Minor Changes to Writer/Mpdf and Writer/Html Changed a sample to illustrate how to add header/footer in Mpdf using setHtmlEditCallback. This uses custom Html tags, and, like body, it appears that these must be defined in the first writeHtml. Adjust writeMpdf to permit this by using a new constant `SIMULATED_BODY_START`, defined as an Html comment, as a delimiter. Sample 21c_Pdf, to which the header/footer code is added, had been introduced with PR #2434 to ensure that the body tag was always in the first chunk. However, PR #3016 accidentally invalidated that test by reducing the number of style lines so that the sample now included the body tag in its first 1000 records rather than afterwards. This change puts it past record 1000 again. Inspecting the results of all the Html/Pdf samples after this change, it turns out that sample 25_In_memory_image was accidentally broken by PR #3535 - the combination of `max-width:100%` (already present before that change) with `position:absolute` (introduced with that change) made the memory drawing disappear from the rendered html when the image occurs in a column after the last column with data in it. It appears that there is no need for max-width (drawings which are not memory drawings do not use it), so it is dropped. The sample is changed to add a second page with a memory drawing, one page with the memory drawing after the last data column, and one with it before. The Html results now reflect the Xlsx result, as they should. * Minor Performance Improvements Anonymous function. --- samples/Basic/25_In_memory_image.php | 37 ++++++++++++++++++-- samples/Pdf/21c_Pdf.php | 48 +++++++++++++++++++++++++- src/PhpSpreadsheet/Writer/Html.php | 17 +++++---- src/PhpSpreadsheet/Writer/Pdf/Mpdf.php | 18 +++++++--- 4 files changed, 103 insertions(+), 17 deletions(-) diff --git a/samples/Basic/25_In_memory_image.php b/samples/Basic/25_In_memory_image.php index af02c64ab..b8cd20e73 100644 --- a/samples/Basic/25_In_memory_image.php +++ b/samples/Basic/25_In_memory_image.php @@ -2,12 +2,18 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; +use PhpOffice\PhpSpreadsheet\Writer\BaseWriter; require __DIR__ . '/../Header.php'; // Create new Spreadsheet object $helper->log('Create new Spreadsheet object'); $spreadsheet = new Spreadsheet(); +$sheet1 = $spreadsheet->getActiveSheet(); +$sheet1->setTitle('SheetWithData'); +$sheet1->getCell('G1')->setValue('X'); +$sheet1->getCell('E5')->setValue('Y'); +$sheet1->getCell('A8')->setValue('Z'); // Set document properties $helper->log('Set document properties'); @@ -38,8 +44,35 @@ $drawing->setImageResource($gdImage); $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG); $drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT); $drawing->setHeight(36); -$drawing->setWorksheet($spreadsheet->getActiveSheet()); +$drawing->setWorksheet($sheet1); +$drawing->setCoordinates('C5'); + +$helper->log('Create new sheet'); +$sheet2 = $spreadsheet->createSheet(); +$sheet2->setTitle('SheetWithoutData'); + +// Add a drawing to the new worksheet +$helper->log('Add a drawing to the new worksheet'); +$drawing = new MemoryDrawing(); +$drawing->setName('Sample image'); +$drawing->setDescription('Sample image'); +$drawing->setImageResource($gdImage); +$drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG); +$drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT); +$drawing->setHeight(36); +$drawing->setWorksheet($sheet2); $drawing->setCoordinates('C5'); // Save -$helper->write($spreadsheet, __FILE__, ['Xlsx', 'Html']); +$helper->write( + $spreadsheet, + __FILE__, + ['Xlsx', 'Html'], + false, + function (BaseWriter $writer): void { + if (method_exists($writer, 'writeAllSheets')) { + $writer->writeAllSheets(); + } + } +); +$spreadsheet->disconnectWorksheets(); diff --git a/samples/Pdf/21c_Pdf.php b/samples/Pdf/21c_Pdf.php index 211f8be9a..f556dcb2f 100644 --- a/samples/Pdf/21c_Pdf.php +++ b/samples/Pdf/21c_Pdf.php @@ -2,15 +2,52 @@ use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf; require __DIR__ . '/../Header.php'; // Issue 2432 - styles were too large to fit in first Mpdf chunk, causing problems. + +function addHeadersFootersMpdf2000(string $html): string +{ + $pagerepl = << + +
+ My document header +
+
+ + + + + + + + +
My documentPage {PAGENO} of {nbpg}{DATE Y-m-j}
+
+ $simulatedBodyStart + + EOF; + + return preg_replace($bodystring, $bodyrepl, $html); +} + $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $counter = 0; $helper->log('Populate spreadsheet'); -for ($row = 1; $row < 501; ++$row) { +for ($row = 1; $row < 1001; ++$row) { $sheet->getCell("A$row")->setValue(++$counter); // Add many styles by using slight variations of font color for each. $sheet->getCell("A$row")->getStyle()->getFont()->getColor()->setRgb(sprintf('%06x', $counter)); @@ -21,4 +58,13 @@ for ($row = 1; $row < 501; ++$row) { $helper->log('Write to Mpdf'); IOFactory::registerWriter('Pdf', \PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf::class); $helper->write($spreadsheet, __FILE__, ['Pdf']); +$helper->write( + $spreadsheet, + __FILE__, + ['Pdf'], + false, + function (Mpdf $writer): void { + $writer->setEditHtmlCallback('addHeadersFootersMpdf2000'); + } +); $spreadsheet->disconnectWorksheets(); diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index f79cf1ae5..53cd86bea 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -504,7 +504,8 @@ class Html extends BaseWriter $html .= $startTag; // Write row if there are HTML table cells in it - if (!isset($this->isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row])) { + $mpdfInvisible = $this->isMPdf && $sheet->getRowDimension($row)->getVisible() === false; + if (!$mpdfInvisible && !isset($this->isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row])) { // Start a new rowData $rowData = []; // Loop through columns @@ -732,9 +733,14 @@ class Html extends BaseWriter // Because of the nature of tables, width is more important than height. // max-width: 100% ensures that image doesnt overflow containing cell + // However, PR #3535 broke test + // 25_In_memory_image, apparently because + // of the use of max-with. In addition, + // non-memory-drawings don't use max-width. + // Its use here is suspect and is being eliminated. // width: X sets width of supplied image. // As a result, images bigger than cell will be contained and images smaller will not get stretched - $html .= '' . $filedesc . ''; } } @@ -1498,10 +1504,6 @@ class Html extends BaseWriter // Sheet index $sheetIndex = $worksheet->getParentOrThrow()->getIndex($worksheet); $html = $this->generateRowStart($worksheet, $sheetIndex, $row); - $generateDiv = $this->isMPdf && $worksheet->getRowDimension($row + 1)->getVisible() === false; - if ($generateDiv) { - $html .= '
' . PHP_EOL; - } // Write cells $colNum = 0; @@ -1546,9 +1548,6 @@ class Html extends BaseWriter } // Write row end - if ($generateDiv) { - $html .= '
' . PHP_EOL; - } $html .= ' ' . PHP_EOL; // Return diff --git a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php index d0ce9ed45..d781483eb 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php @@ -3,11 +3,13 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Pdf; use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup; -use PhpOffice\PhpSpreadsheet\Writer\Html; use PhpOffice\PhpSpreadsheet\Writer\Pdf; class Mpdf extends Pdf { + public const SIMULATED_BODY_START = ''; + private const BODY_TAG = ''; + /** @var bool */ protected $isMPdf = true; @@ -61,16 +63,22 @@ class Mpdf extends Pdf $pdf->SetCreator($this->spreadsheet->getProperties()->getCreator()); $html = $this->generateHTMLAll(); - $bodyLocation = strpos($html, Html::BODY_LINE); + $bodyLocation = strpos($html, self::SIMULATED_BODY_START); + if ($bodyLocation === false) { + $bodyLocation = strpos($html, self::BODY_TAG); + if ($bodyLocation !== false) { + $bodyLocation += strlen(self::BODY_TAG); + } + } // Make sure first data presented to Mpdf includes body tag + // (and any htmlpageheader/htmlpagefooter tags) // so that Mpdf doesn't parse it as content. Issue 2432. if ($bodyLocation !== false) { - $bodyLocation += strlen(Html::BODY_LINE); $pdf->WriteHTML(substr($html, 0, $bodyLocation)); $html = substr($html, $bodyLocation); } - foreach (\array_chunk(\explode(PHP_EOL, $html), 1000) as $lines) { - $pdf->WriteHTML(\implode(PHP_EOL, $lines)); + foreach (explode("\n", $html) as $line) { + $pdf->WriteHTML("$line\n"); } // Write to file