Skip to content

Commit ee2d4e8

Browse files
authored
Merge pull request #4711 from oleibman/printarea
Limited PrintArea Support for Html/Pdf
2 parents dcf475e + 8108c12 commit ee2d4e8

File tree

7 files changed

+312
-16
lines changed

7 files changed

+312
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). Thia is a
99

1010
### Added
1111

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

1414
### Removed
1515

src/PhpSpreadsheet/Reader/Html.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,10 @@ private function processDomElementTable(Worksheet $sheet, int &$row, string &$co
533533
$sheet->setShowGridlines(in_array('gridlines', $classes, true));
534534
$sheet->setPrintGridlines(in_array('gridlinesp', $classes, true));
535535
}
536+
if (isset($attributeArray['data-printarea'])) {
537+
$sheet->getPageSetup()
538+
->setPrintArea($attributeArray['data-printarea']);
539+
}
536540
if ('rtl' === ($attributeArray['dir'] ?? '')) {
537541
$sheet->setRightToLeft(true);
538542
}

src/PhpSpreadsheet/Writer/Html.php

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,14 @@ private function generateSheetTags(int $row, int $theadStart, int $theadEnd, int
511511
return [$cellType, $startTag, $endTag];
512512
}
513513

514+
private int $printAreaLowRow = -1;
515+
516+
private int $printAreaHighRow = -1;
517+
518+
private int $printAreaLowCol = -1;
519+
520+
private int $printAreaHighCol = -1;
521+
514522
/**
515523
* Generate sheet data.
516524
*/
@@ -529,6 +537,17 @@ public function generateSheetData(): string
529537
$activeSheet = $this->spreadsheet->getActiveSheetIndex();
530538

531539
foreach ($sheets as $sheet) {
540+
$this->printAreaLowRow = -1;
541+
$this->printAreaHighRow = -1;
542+
$this->printAreaLowCol = -1;
543+
$this->printAreaHighCol = -1;
544+
$printArea = $sheet->getPageSetup()->getPrintArea();
545+
if (Preg::isMatch('/^([a-z]+)([0-9]+):([a-z]+)([0-9]+)$/i', $printArea, $matches)) {
546+
$this->printAreaLowCol = Coordinate::columnIndexFromString($matches[1]);
547+
$this->printAreaHighCol = Coordinate::columnIndexFromString($matches[3]);
548+
$this->printAreaLowRow = (int) $matches[2];
549+
$this->printAreaHighRow = (int) $matches[4];
550+
}
532551
// save active cells
533552
$selectedCells = $sheet->getSelectedCells();
534553
// Write table header
@@ -1308,16 +1327,18 @@ private function generateTableTagInline(Worksheet $worksheet, string $id): strin
13081327
$float = $this->getFloat($worksheet);
13091328
$prntgrid = $worksheet->getPrintGridlines();
13101329
$viewgrid = $this->isPdf ? $prntgrid : $worksheet->getShowGridlines();
1330+
$printArea = $worksheet->getPageSetup()->getPrintArea();
1331+
$dataPrint = ($printArea === '') ? '' : (" data-printarea='" . htmlspecialchars($printArea) . "'");
13111332
if ($viewgrid && $prntgrid) {
1312-
$html = " <table border='1' cellpadding='1'$rtl $id cellspacing='1' style='$style' class='gridlines gridlinesp$float'>" . PHP_EOL;
1333+
$html = " <table border='1' cellpadding='1'$rtl$dataPrint $id cellspacing='1' style='$style' class='gridlines gridlinesp$float'>" . PHP_EOL;
13131334
} elseif ($viewgrid) {
1314-
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlines$float'>" . PHP_EOL;
1335+
$html = " <table border='0' cellpadding='0'$rtl$dataPrint $id cellspacing='0' style='$style' class='gridlines$float'>" . PHP_EOL;
13151336
} elseif ($prntgrid) {
1316-
$html = " <table border='0' cellpadding='0'$rtl $id cellspacing='0' style='$style' class='gridlinesp$float'>" . PHP_EOL;
1337+
$html = " <table border='0' cellpadding='0'$rtl$dataPrint $id cellspacing='0' style='$style' class='gridlinesp$float'>" . PHP_EOL;
13171338
} elseif ($float === '') {
1318-
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style'>" . PHP_EOL;
1339+
$html = " <table border='0' cellpadding='1'$rtl$dataPrint $id cellspacing='0' style='$style'>" . PHP_EOL;
13191340
} else {
1320-
$html = " <table border='0' cellpadding='1'$rtl $id cellspacing='0' style='$style' class='$float'>" . PHP_EOL;
1341+
$html = " <table border='0' cellpadding='1'$rtl$dataPrint $id cellspacing='0' style='$style' class='$float'>" . PHP_EOL;
13211342
}
13221343

13231344
return $html;
@@ -1327,10 +1348,12 @@ private function generateTableTag(Worksheet $worksheet, string $id, string &$htm
13271348
{
13281349
if (!$this->useInlineCss) {
13291350
$rtl = $this->getDir($worksheet);
1351+
$printArea = $worksheet->getPageSetup()->getPrintArea();
1352+
$dataPrint = ($printArea === '') ? '' : (" data-printarea='" . htmlspecialchars($printArea) . "'");
13301353
$float = $this->getFloat($worksheet);
13311354
$gridlines = $worksheet->getShowGridlines() ? ' gridlines' : '';
13321355
$gridlinesp = $worksheet->getPrintGridlines() ? ' gridlinesp' : '';
1333-
$html .= " <table border='0' cellpadding='0' cellspacing='0'$rtl $id class='sheet$sheetIndex$gridlines$gridlinesp$float'>" . PHP_EOL;
1356+
$html .= " <table border='0' cellpadding='0' cellspacing='0'$rtl$dataPrint $id class='sheet$sheetIndex$gridlines$gridlinesp$float'>" . PHP_EOL;
13341357
} else {
13351358
$html .= $this->generateTableTagInline($worksheet, $id);
13361359
}
@@ -1797,7 +1820,7 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
17971820
$colNum = $key - 1;
17981821
if (!$tcpdfInited && $key !== 1) {
17991822
$tempspan = ($colNum > 1) ? " colspan='$colNum'" : '';
1800-
$html .= "<td$tempspan></td>\n";
1823+
$html .= "<td$tempspan></td>" . PHP_EOL;
18011824
}
18021825
$tcpdfInited = true;
18031826
}
@@ -1873,17 +1896,11 @@ private function generateRow(Worksheet $worksheet, array $values, int $row, stri
18731896
return $html;
18741897
}
18751898

1876-
/** @param string[] $matches */
1877-
private static function replaceNonAscii(array $matches): string
1878-
{
1879-
return '&#' . mb_ord($matches[0], 'UTF-8') . ';';
1880-
}
1881-
18821899
private static function replaceControlChars(string $convert): string
18831900
{
1884-
return (string) preg_replace_callback(
1901+
return Preg::replaceCallback(
18851902
'/[\x00-\x1f]/',
1886-
[self::class, 'replaceNonAscii'],
1903+
fn (array $matches) => '&#' . ord($matches[0]) . ';',
18871904
$convert
18881905
);
18891906
}
@@ -2199,6 +2216,9 @@ private function generatePageDeclarations(bool $generateSurroundingHTML): string
21992216
$htmlPage .= 'size: portrait; ';
22002217
}
22012218
$htmlPage .= '}' . PHP_EOL;
2219+
if (!$this->isPdf) {
2220+
$htmlPage .= $this->printAreaStyles($sheetId, $worksheet);
2221+
}
22022222
++$sheetId;
22032223
}
22042224
$htmlPage .= implode(PHP_EOL, [
@@ -2223,8 +2243,44 @@ private function generatePageDeclarations(bool $generateSurroundingHTML): string
22232243
return $htmlPage;
22242244
}
22252245

2246+
private function printAreaStyles(int $sheetId, Worksheet $worksheet): string
2247+
{
2248+
$retVal = '';
2249+
$printArea = $worksheet->getPageSetup()->getPrintArea();
2250+
if (Preg::isMatch('/^([a-z]+)([0-9]+):([a-z]+)([0-9]+)$/i', $printArea, $matches)) {
2251+
$lowCol = Coordinate::columnIndexFromString($matches[1]) - 1;
2252+
$highCol = Coordinate::columnIndexFromString($matches[3]) - 1;
2253+
$lowRow = (int) $matches[2] - 1;
2254+
$highRow = (int) $matches[4] - 1;
2255+
$retVal = '@media print {' . PHP_EOL;
2256+
$highDataRow = $worksheet->getHighestDataRow();
2257+
for ($row = 0; $row < $highDataRow; ++$row) {
2258+
if ($row < $lowRow || $row > $highRow) {
2259+
$retVal .= " table.sheet$sheetId tr.row$row td { display:none }" . PHP_EOL;
2260+
}
2261+
}
2262+
$highDataColumn = $worksheet->getHighestDataColumn();
2263+
$highDataCol = Coordinate::columnIndexFromString($highDataColumn);
2264+
for ($col = 0; $col < $highDataCol; ++$col) {
2265+
if ($col < $lowCol || $col > $highCol) {
2266+
$retVal .= " table.sheet$sheetId td.column$col { display:none }" . PHP_EOL;
2267+
}
2268+
}
2269+
$retVal .= '}' . PHP_EOL;
2270+
}
2271+
2272+
return $retVal;
2273+
}
2274+
22262275
private function shouldGenerateRow(Worksheet $sheet, int $row): bool
22272276
{
2277+
if ($this->isPdf) {
2278+
if ($this->printAreaLowRow >= 0) {
2279+
if ($row < $this->printAreaLowRow || $row > $this->printAreaHighRow) {
2280+
return false;
2281+
}
2282+
}
2283+
}
22282284
if (!($this instanceof Pdf\Mpdf || $this instanceof Pdf\Tcpdf)) {
22292285
return true;
22302286
}
@@ -2234,6 +2290,14 @@ private function shouldGenerateRow(Worksheet $sheet, int $row): bool
22342290

22352291
private function shouldGenerateColumn(Worksheet $sheet, string $colStr): bool
22362292
{
2293+
if ($this->isPdf) {
2294+
if ($this->printAreaLowCol >= 0) {
2295+
$col = Coordinate::columnIndexFromString($colStr);
2296+
if ($col < $this->printAreaLowCol || $col > $this->printAreaHighCol) {
2297+
return false;
2298+
}
2299+
}
2300+
}
22372301
if (!($this instanceof Pdf\Mpdf || $this instanceof Pdf\Tcpdf)) {
22382302
return true;
22392303
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Dompdf;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Dompdf as DompdfWriter;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class PrintAreaTest extends TestCase
12+
{
13+
public function testPrintArea(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$sheet = $spreadsheet->getActiveSheet();
17+
$inArray = [
18+
[1, 2, 3, 4, 5],
19+
[6, 7, 8, 9, 10],
20+
[11, 12, 13, 14, 15],
21+
[16, 17, 18, 19, 20],
22+
[21, 22, 23, 24, 25],
23+
[26, 27, 28, 29, 30],
24+
];
25+
$sheet->fromArray($inArray);
26+
$sheet->getPageSetup()->setPrintArea('B2:D4');
27+
$writer = new DompdfWriter($spreadsheet);
28+
$html = $writer->generateHtmlAll();
29+
$html = preg_replace('/^ +/m', '', $html) ?? $html;
30+
$expectedArray = [
31+
'<tbody>',
32+
'<tr class="row1">',
33+
'<td class="column0 style0 n" style="width:42pt">7</td>',
34+
'<td class="column1 style0 n" style="width:42pt">8</td>',
35+
'<td class="column2 style0 n" style="width:42pt">9</td>',
36+
'</tr>',
37+
'<tr class="row2">',
38+
'<td class="column0 style0 n" style="width:42pt">12</td>',
39+
'<td class="column1 style0 n" style="width:42pt">13</td>',
40+
'<td class="column2 style0 n" style="width:42pt">14</td>',
41+
'</tr>',
42+
'<tr class="row3">',
43+
'<td class="column0 style0 n" style="width:42pt">17</td>',
44+
'<td class="column1 style0 n" style="width:42pt">18</td>',
45+
'<td class="column2 style0 n" style="width:42pt">19</td>',
46+
'</tr>',
47+
'</tbody>',
48+
];
49+
$expectedString = implode(PHP_EOL, $expectedArray);
50+
self::assertStringContainsString(
51+
$expectedString,
52+
$html
53+
);
54+
$spreadsheet->disconnectWorksheets();
55+
}
56+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;
6+
7+
use PhpOffice\PhpSpreadsheet\Reader\Html as HtmlReader;
8+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9+
use PhpOffice\PhpSpreadsheet\Writer\Html as HtmlWriter;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class PrintAreaTest extends TestCase
13+
{
14+
public function testPrintArea(): void
15+
{
16+
$spreadsheet = new Spreadsheet();
17+
$sheet = $spreadsheet->getActiveSheet();
18+
$inArray = [
19+
[1, 2, 3, 4, 5],
20+
[6, 7, 8, 9, 10],
21+
[11, 12, 13, 14, 15],
22+
[16, 17, 18, 19, 20],
23+
[21, 22, 23, 24, 25],
24+
[26, 27, 28, 29, 30],
25+
];
26+
$sheet->fromArray($inArray);
27+
$sheet->getPageSetup()->setPrintArea('B2:D4');
28+
$writer = new HtmlWriter($spreadsheet);
29+
$html = $writer->generateHtmlAll();
30+
self::assertStringContainsString(
31+
"<table border='0' cellpadding='0' cellspacing='0' data-printarea='B2:D4' id='sheet0' class='sheet0 gridlines'>",
32+
$html
33+
);
34+
$expectedArray = [
35+
'@media print {',
36+
' table.sheet0 tr.row0 td { display:none }',
37+
' table.sheet0 tr.row4 td { display:none }',
38+
' table.sheet0 tr.row5 td { display:none }',
39+
' table.sheet0 td.column0 { display:none }',
40+
' table.sheet0 td.column4 { display:none }',
41+
'}',
42+
];
43+
$expectedString = implode(PHP_EOL, $expectedArray);
44+
self::assertStringContainsString(
45+
$expectedString,
46+
$html
47+
);
48+
$spreadsheet->disconnectWorksheets();
49+
50+
$reader = new HtmlReader();
51+
$spreadsheet2 = $reader->loadFromString($html);
52+
$sheet2 = $spreadsheet2->getActiveSheet();
53+
self::assertSame('B2:D4', $sheet2->getPageSetup()->getPrintArea());
54+
self::assertSame($inArray, $sheet2->toArray(null, false, false));
55+
$spreadsheet2->disconnectWorksheets();
56+
}
57+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpOffice\PhpSpreadsheetTests\Writer\Mpdf;
6+
7+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8+
use PhpOffice\PhpSpreadsheet\Writer\Pdf\Mpdf as MpdfWriter;
9+
use PHPUnit\Framework\TestCase;
10+
11+
class PrintAreaTest extends TestCase
12+
{
13+
public function testPrintArea(): void
14+
{
15+
$spreadsheet = new Spreadsheet();
16+
$sheet = $spreadsheet->getActiveSheet();
17+
$inArray = [
18+
[1, 2, 3, 4, 5],
19+
[6, 7, 8, 9, 10],
20+
[11, 12, 13, 14, 15],
21+
[16, 17, 18, 19, 20],
22+
[21, 22, 23, 24, 25],
23+
[26, 27, 28, 29, 30],
24+
];
25+
$sheet->fromArray($inArray);
26+
$sheet->getPageSetup()->setPrintArea('B2:D4');
27+
$writer = new MpdfWriter($spreadsheet);
28+
$html = $writer->generateHtmlAll();
29+
$html = preg_replace('/^ +/m', '', $html) ?? $html;
30+
$expectedArray = [
31+
'<tbody>',
32+
'<tr class="row1">',
33+
'<td class="column1 style0 n" style="width:42pt">7</td>',
34+
'<td class="column2 style0 n" style="width:42pt">8</td>',
35+
'<td class="column3 style0 n" style="width:42pt">9</td>',
36+
'</tr>',
37+
'<tr class="row2">',
38+
'<td class="column1 style0 n" style="width:42pt">12</td>',
39+
'<td class="column2 style0 n" style="width:42pt">13</td>',
40+
'<td class="column3 style0 n" style="width:42pt">14</td>',
41+
'</tr>',
42+
'<tr class="row3">',
43+
'<td class="column1 style0 n" style="width:42pt">17</td>',
44+
'<td class="column2 style0 n" style="width:42pt">18</td>',
45+
'<td class="column3 style0 n" style="width:42pt">19</td>',
46+
'</tr>',
47+
'</tbody>',
48+
];
49+
$expectedString = implode(PHP_EOL, $expectedArray);
50+
self::assertStringContainsString(
51+
$expectedString,
52+
$html
53+
);
54+
$spreadsheet->disconnectWorksheets();
55+
}
56+
}

0 commit comments

Comments
 (0)