Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a

### Added

- Nothing yet.
- Limited Printarea support for Html/Pdf. [Issue #3941](https://github.com/PHPOffice/PhpSpreadsheet/issues/3941) [PR #4711](https://github.com/PHPOffice/PhpSpreadsheet/pull/4711)

### Removed

Expand Down
4 changes: 4 additions & 0 deletions src/PhpSpreadsheet/Reader/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,10 @@ private function processDomElementTable(Worksheet $sheet, int &$row, string &$co
$sheet->setShowGridlines(in_array('gridlines', $classes, true));
$sheet->setPrintGridlines(in_array('gridlinesp', $classes, true));
}
if (isset($attributeArray['data-printarea'])) {
$sheet->getPageSetup()
->setPrintArea($attributeArray['data-printarea']);
}
if ('rtl' === ($attributeArray['dir'] ?? '')) {
$sheet->setRightToLeft(true);
}
Expand Down
94 changes: 79 additions & 15 deletions src/PhpSpreadsheet/Writer/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,14 @@ private function generateSheetTags(int $row, int $theadStart, int $theadEnd, int
return [$cellType, $startTag, $endTag];
}

private int $printAreaLowRow = -1;

private int $printAreaHighRow = -1;

private int $printAreaLowCol = -1;

private int $printAreaHighCol = -1;

/**
* Generate sheet data.
*/
Expand All @@ -529,6 +537,17 @@ public function generateSheetData(): string
$activeSheet = $this->spreadsheet->getActiveSheetIndex();

foreach ($sheets as $sheet) {
$this->printAreaLowRow = -1;
$this->printAreaHighRow = -1;
$this->printAreaLowCol = -1;
$this->printAreaHighCol = -1;
$printArea = $sheet->getPageSetup()->getPrintArea();
if (Preg::isMatch('/^([a-z]+)([0-9]+):([a-z]+)([0-9]+)$/i', $printArea, $matches)) {
$this->printAreaLowCol = Coordinate::columnIndexFromString($matches[1]);
$this->printAreaHighCol = Coordinate::columnIndexFromString($matches[3]);
$this->printAreaLowRow = (int) $matches[2];
$this->printAreaHighRow = (int) $matches[4];
}
// save active cells
$selectedCells = $sheet->getSelectedCells();
// Write table header
Expand Down Expand Up @@ -1308,16 +1327,18 @@ private function generateTableTagInline(Worksheet $worksheet, string $id): strin
$float = $this->getFloat($worksheet);
$prntgrid = $worksheet->getPrintGridlines();
$viewgrid = $this->isPdf ? $prntgrid : $worksheet->getShowGridlines();
$printArea = $worksheet->getPageSetup()->getPrintArea();
$dataPrint = ($printArea === '') ? '' : (" data-printarea='" . htmlspecialchars($printArea) . "'");
if ($viewgrid && $prntgrid) {
$html = " <table border='1' cellpadding='1'$rtl $id cellspacing='1' style='$style' class='gridlines gridlinesp$float'>" . PHP_EOL;
$html = " <table border='1' cellpadding='1'$rtl$dataPrint $id cellspacing='1' style='$style' class='gridlines gridlinesp$float'>" . PHP_EOL;
} elseif ($viewgrid) {
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlines$float'>" . PHP_EOL;
$html = " <table border='0' cellpadding='0'$rtl$dataPrint $id cellspacing='0' style='$style' class='gridlines$float'>" . PHP_EOL;
} elseif ($prntgrid) {
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlinesp$float'>" . PHP_EOL;
$html = " <table border='0' cellpadding='0'$rtl$dataPrint $id cellspacing='0' style='$style' class='gridlinesp$float'>" . PHP_EOL;
} elseif ($float === '') {
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style'>" . PHP_EOL;
$html = " <table border='0' cellpadding='1'$rtl$dataPrint $id cellspacing='0' style='$style'>" . PHP_EOL;
} else {
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style' class='$float'>" . PHP_EOL;
$html = " <table border='0' cellpadding='1'$rtl$dataPrint $id cellspacing='0' style='$style' class='$float'>" . PHP_EOL;
}

return $html;
Expand All @@ -1327,10 +1348,12 @@ private function generateTableTag(Worksheet $worksheet, string $id, string &$htm
{
if (!$this->useInlineCss) {
$rtl = $this->getDir($worksheet);
$printArea = $worksheet->getPageSetup()->getPrintArea();
$dataPrint = ($printArea === '') ? '' : (" data-printarea='" . htmlspecialchars($printArea) . "'");
$float = $this->getFloat($worksheet);
$gridlines = $worksheet->getShowGridlines() ? ' gridlines' : '';
$gridlinesp = $worksheet->getPrintGridlines() ? ' gridlinesp' : '';
$html .= " <table border='0' cellpadding='0' cellspacing='0'$rtl $id class='sheet$sheetIndex$gridlines$gridlinesp$float'>" . PHP_EOL;
$html .= " <table border='0' cellpadding='0' cellspacing='0'$rtl$dataPrint $id class='sheet$sheetIndex$gridlines$gridlinesp$float'>" . PHP_EOL;
} else {
$html .= $this->generateTableTagInline($worksheet, $id);
}
Expand Down Expand Up @@ -1797,7 +1820,7 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
$colNum = $key - 1;
if (!$tcpdfInited && $key !== 1) {
$tempspan = ($colNum > 1) ? " colspan='$colNum'" : '';
$html .= "<td$tempspan></td>\n";
$html .= "<td$tempspan></td>" . PHP_EOL;
}
$tcpdfInited = true;
}
Expand Down Expand Up @@ -1873,17 +1896,11 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
return $html;
}

/** @param string[] $matches */
private static function replaceNonAscii(array $matches): string
{
return '&#' . mb_ord($matches[0], 'UTF-8') . ';';
}

private static function replaceControlChars(string $convert): string
{
return (string) preg_replace_callback(
return Preg::replaceCallback(
'/[\x00-\x1f]/',
[self::class, 'replaceNonAscii'],
fn (array $matches) => '&#' . ord($matches[0]) . ';',
$convert
);
}
Expand Down Expand Up @@ -2199,6 +2216,9 @@ private function generatePageDeclarations(bool $generateSurroundingHTML): string
$htmlPage .= 'size: portrait; ';
}
$htmlPage .= '}' . PHP_EOL;
if (!$this->isPdf) {
$htmlPage .= $this->printAreaStyles($sheetId, $worksheet);
}
++$sheetId;
}
$htmlPage .= implode(PHP_EOL, [
Expand All @@ -2223,8 +2243,44 @@ private function generatePageDeclarations(bool $generateSurroundingHTML): string
return $htmlPage;
}

private function printAreaStyles(int $sheetId, Worksheet $worksheet): string
{
$retVal = '';
$printArea = $worksheet->getPageSetup()->getPrintArea();
if (Preg::isMatch('/^([a-z]+)([0-9]+):([a-z]+)([0-9]+)$/i', $printArea, $matches)) {
$lowCol = Coordinate::columnIndexFromString($matches[1]) - 1;
$highCol = Coordinate::columnIndexFromString($matches[3]) - 1;
$lowRow = (int) $matches[2] - 1;
$highRow = (int) $matches[4] - 1;
$retVal = '@media print {' . PHP_EOL;
$highDataRow = $worksheet->getHighestDataRow();
for ($row = 0; $row < $highDataRow; ++$row) {
if ($row < $lowRow || $row > $highRow) {
$retVal .= " table.sheet$sheetId tr.row$row td { display:none }" . PHP_EOL;
}
}
$highDataColumn = $worksheet->getHighestDataColumn();
$highDataCol = Coordinate::columnIndexFromString($highDataColumn);
for ($col = 0; $col < $highDataCol; ++$col) {
if ($col < $lowCol || $col > $highCol) {
$retVal .= " table.sheet$sheetId td.column$col { display:none }" . PHP_EOL;
}
}
$retVal .= '}' . PHP_EOL;
}

return $retVal;
}

private function shouldGenerateRow(Worksheet $sheet, int $row): bool
{
if ($this->isPdf) {
if ($this->printAreaLowRow >= 0) {
if ($row < $this->printAreaLowRow || $row > $this->printAreaHighRow) {
return false;
}
}
}
if (!($this instanceof Pdf\Mpdf || $this instanceof Pdf\Tcpdf)) {
return true;
}
Expand All @@ -2234,6 +2290,14 @@ private function shouldGenerateRow(Worksheet $sheet, int $row): bool

private function shouldGenerateColumn(Worksheet $sheet, string $colStr): bool
{
if ($this->isPdf) {
if ($this->printAreaLowCol >= 0) {
$col = Coordinate::columnIndexFromString($colStr);
if ($col < $this->printAreaLowCol || $col > $this->printAreaHighCol) {
return false;
}
}
}
if (!($this instanceof Pdf\Mpdf || $this instanceof Pdf\Tcpdf)) {
return true;
}
Expand Down
56 changes: 56 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Dompdf/PrintAreaTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Dompdf;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf as DompdfWriter;
use PHPUnit\Framework\TestCase;

class PrintAreaTest extends TestCase
{
public function testPrintArea(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$inArray = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
];
$sheet->fromArray($inArray);
$sheet->getPageSetup()->setPrintArea('B2:D4');
$writer = new DompdfWriter($spreadsheet);
$html = $writer->generateHtmlAll();
$html = preg_replace('/^ +/m', '', $html) ?? $html;
$expectedArray = [
'<tbody>',
'<tr class="row1">',
'<td class="column0 style0 n" style="width:42pt">7</td>',
'<td class="column1 style0 n" style="width:42pt">8</td>',
'<td class="column2 style0 n" style="width:42pt">9</td>',
'</tr>',
'<tr class="row2">',
'<td class="column0 style0 n" style="width:42pt">12</td>',
'<td class="column1 style0 n" style="width:42pt">13</td>',
'<td class="column2 style0 n" style="width:42pt">14</td>',
'</tr>',
'<tr class="row3">',
'<td class="column0 style0 n" style="width:42pt">17</td>',
'<td class="column1 style0 n" style="width:42pt">18</td>',
'<td class="column2 style0 n" style="width:42pt">19</td>',
'</tr>',
'</tbody>',
];
$expectedString = implode(PHP_EOL, $expectedArray);
self::assertStringContainsString(
$expectedString,
$html
);
$spreadsheet->disconnectWorksheets();
}
}
57 changes: 57 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Html/PrintAreaTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\Reader\Html as HtmlReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
use PHPUnit\Framework\TestCase;

class PrintAreaTest extends TestCase
{
public function testPrintArea(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$inArray = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
];
$sheet->fromArray($inArray);
$sheet->getPageSetup()->setPrintArea('B2:D4');
$writer = new HtmlWriter($spreadsheet);
$html = $writer->generateHtmlAll();
self::assertStringContainsString(
"<table border='0' cellpadding='0' cellspacing='0' data-printarea='B2:D4' id='sheet0' class='sheet0 gridlines'>",
$html
);
$expectedArray = [
'@media print {',
' table.sheet0 tr.row0 td { display:none }',
' table.sheet0 tr.row4 td { display:none }',
' table.sheet0 tr.row5 td { display:none }',
' table.sheet0 td.column0 { display:none }',
' table.sheet0 td.column4 { display:none }',
'}',
];
$expectedString = implode(PHP_EOL, $expectedArray);
self::assertStringContainsString(
$expectedString,
$html
);
$spreadsheet->disconnectWorksheets();

$reader = new HtmlReader();
$spreadsheet2 = $reader->loadFromString($html);
$sheet2 = $spreadsheet2->getActiveSheet();
self::assertSame('B2:D4', $sheet2->getPageSetup()->getPrintArea());
self::assertSame($inArray, $sheet2->toArray(null, false, false));
$spreadsheet2->disconnectWorksheets();
}
}
56 changes: 56 additions & 0 deletions tests/PhpSpreadsheetTests/Writer/Mpdf/PrintAreaTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Mpdf;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf as MpdfWriter;
use PHPUnit\Framework\TestCase;

class PrintAreaTest extends TestCase
{
public function testPrintArea(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$inArray = [
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28, 29, 30],
];
$sheet->fromArray($inArray);
$sheet->getPageSetup()->setPrintArea('B2:D4');
$writer = new MpdfWriter($spreadsheet);
$html = $writer->generateHtmlAll();
$html = preg_replace('/^ +/m', '', $html) ?? $html;
$expectedArray = [
'<tbody>',
'<tr class="row1">',
'<td class="column1 style0 n" style="width:42pt">7</td>',
'<td class="column2 style0 n" style="width:42pt">8</td>',
'<td class="column3 style0 n" style="width:42pt">9</td>',
'</tr>',
'<tr class="row2">',
'<td class="column1 style0 n" style="width:42pt">12</td>',
'<td class="column2 style0 n" style="width:42pt">13</td>',
'<td class="column3 style0 n" style="width:42pt">14</td>',
'</tr>',
'<tr class="row3">',
'<td class="column1 style0 n" style="width:42pt">17</td>',
'<td class="column2 style0 n" style="width:42pt">18</td>',
'<td class="column3 style0 n" style="width:42pt">19</td>',
'</tr>',
'</tbody>',
];
$expectedString = implode(PHP_EOL, $expectedArray);
self::assertStringContainsString(
$expectedString,
$html
);
$spreadsheet->disconnectWorksheets();
}
}
Loading