Skip to content

Support pageOrder in page setup for Xlsx/Xls Readers/Writers, and implement basic page setup support for other Readers/Writers #1559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Jul 26, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a0bba38
Support pageOrder in page setup for Xlsx Reader and Writer
Jun 29, 2020
21b34f0
pageOrder is nullable
Jun 29, 2020
362b18c
Read Print Settings Page Order in Xls Reader
Jun 29, 2020
4060cde
Fix comment
Jun 29, 2020
fbb04c1
Xls Writer changes to save print order
Jun 30, 2020
1f865c8
Keep phpcs happy
Jun 30, 2020
3780072
Retrieve basic print settings in the Ods Reader
Jun 30, 2020
13a3363
Return void, just to keep phpcs happy
Jun 30, 2020
4dadf4a
Refactor reading Ods Page Settings into a separate class
Jun 30, 2020
736d9ff
Gotta keep phpcs happy, even if it is only a blank line between prope…
Jun 30, 2020
163da06
Horizontal an dVertical centering for the Ods Reader
Jul 1, 2020
e644cc7
Additional print information for Gnumeric
Jul 1, 2020
c288c11
Failed to avoid the void trap
Jul 1, 2020
aecef13
Read Ods Margins
Jul 3, 2020
84ba214
Fix datatype conversion for Gnumeric values
Jul 3, 2020
8629337
Retrieving print/page setup for the Xml Reader
Jul 5, 2020
d009347
Forgot to check in the test files for the unit tests
Jul 5, 2020
3997dcc
Not sure why PHP 7.4 should suddenly have decided to report a notice …
Jul 5, 2020
e89196f
phpcs fixes, although I thought I'd successfully added the pre-commit…
Jul 5, 2020
cf6769e
Hopefully a final phpcs fix before I start looking at how to run a pr…
Jul 5, 2020
961dc69
Improve SCrutinizer happiness
Jul 5, 2020
586b36b
Refactor Xml PageSettings into a separate loader class
Jul 5, 2020
6cbb622
Minor refactoring
Jul 5, 2020
f3fc321
Gah! Using PHPStorm refactor changes the formatting, so valid code su…
Jul 5, 2020
c6de56e
Minor refactoring
Jul 5, 2020
d4094c0
Minor refactoring
Jul 5, 2020
47eb3e9
Update Change Log
Jul 5, 2020
c3fa31d
Missing typing
PowerKiKi Jul 19, 2020
395b750
Stricter visibility
PowerKiKi Jul 19, 2020
5233e9c
Merge branch 'master' into Page-Setup-Page-Order
Jul 19, 2020
0489e78
Merge branch 'master' into Page-Setup-Page-Order
PowerKiKi Jul 26, 2020
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).

### Added

- nothing
- Implemented Page Order for Xlsx and Xls Readers, and provided Page Settings (Orientation, Scale, Horizontal/Vertical Centering, Page Order, Margins) support for Ods, Gnumeric and Xls Readers [#1559](https://github.com/PHPOffice/PhpSpreadsheet/pull/1559)

### Fixed

Expand Down
56 changes: 8 additions & 48 deletions src/PhpSpreadsheet/Reader/Gnumeric.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\NamedRange;
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric\PageSetup;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\ReferenceHelper;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
Expand All @@ -23,6 +24,8 @@

class Gnumeric extends BaseReader
{
private const UOM_CONVERSION_POINTS_TO_CENTIMETERS = 0.03527777778;

/**
* Shared Expressions.
*
Expand Down Expand Up @@ -401,53 +404,6 @@ private function docProperties(SimpleXMLElement $xml, SimpleXMLElement $gnmXML,
}
}

private function sheetMargin(string $key, float $marginSize): void
{
switch ($key) {
case 'top':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setTop($marginSize);

break;
case 'bottom':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setBottom($marginSize);

break;
case 'left':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setLeft($marginSize);

break;
case 'right':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setRight($marginSize);

break;
case 'header':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setHeader($marginSize);

break;
case 'footer':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setFooter($marginSize);

break;
}
}

private function sheetMargins(SimpleXMLElement $sheet): void
{
if (!$this->readDataOnly && isset($sheet->PrintInformation, $sheet->PrintInformation->Margins)) {
foreach ($sheet->PrintInformation->Margins->children($this->gnm, true) as $key => $margin) {
$marginAttributes = $margin->attributes();
$marginSize = 72 / 100; // Default
switch ($marginAttributes['PrefUnit']) {
case 'mm':
$marginSize = (int) ($marginAttributes['Points']) / 100;

break;
}
$this->sheetMargin($key, (float) $marginSize);
}
}
}

private function processComments(SimpleXMLElement $sheet): void
{
if ((!$this->readDataOnly) && (isset($sheet->Objects))) {
Expand Down Expand Up @@ -513,7 +469,11 @@ public function loadIntoExisting(string $pFilename, Spreadsheet $spreadsheet): S
// name in line with the formula, not the reverse
$this->spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);

$this->sheetMargins($sheet);
if (!$this->readDataOnly) {
(new PageSetup($this->spreadsheet, $this->gnm))
->printInformation($sheet)
->sheetMargins($sheet);
}

foreach ($sheet->Cells->Cell as $cell) {
$cellAttributes = $cell->attributes();
Expand Down
143 changes: 143 additions & 0 deletions src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
<?php

namespace PhpOffice\PhpSpreadsheet\Reader\Gnumeric;

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageMargins;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup as WorksheetPageSetup;
use SimpleXMLElement;

class PageSetup
{
/**
* @var Spreadsheet
*/
private $spreadsheet;

/**
* @var string
*/
private $gnm;

public function __construct(Spreadsheet $spreadsheet, $gnm)
{
$this->spreadsheet = $spreadsheet;
$this->gnm = $gnm;
}

public function printInformation(SimpleXMLElement $sheet): self
{
if (isset($sheet->PrintInformation)) {
$printInformation = $sheet->PrintInformation[0];
$scale = (string) $printInformation->Scale->attributes()['percentage'];
$pageOrder = (string) $printInformation->order;
$orientation = (string) $printInformation->orientation;
$horizontalCentered = (string) $printInformation->hcenter->attributes()['value'];
$verticalCentered = (string) $printInformation->vcenter->attributes()['value'];

$this->spreadsheet->getActiveSheet()->getPageSetup()
->setPageOrder($pageOrder === 'r_then_d' ? WorksheetPageSetup::PAGEORDER_OVER_THEN_DOWN : WorksheetPageSetup::PAGEORDER_DOWN_THEN_OVER)
->setScale((int) $scale)
->setOrientation($orientation ?? WorksheetPageSetup::ORIENTATION_DEFAULT)
->setHorizontalCentered((bool) $horizontalCentered)
->setVerticalCentered((bool) $verticalCentered);
}

return $this;
}

public function sheetMargins(SimpleXMLElement $sheet): self
{
if (isset($sheet->PrintInformation, $sheet->PrintInformation->Margins)) {
$marginSet = [
// Default Settings
'top' => 0.75,
'header' => 0.3,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.75,
'footer' => 0.3,
];

$marginSet = $this->buildMarginSet($sheet, $marginSet);
$this->adjustMargins($marginSet);
}

return $this;
}

private function buildMarginSet(SimpleXMLElement $sheet, array $marginSet): array
{
foreach ($sheet->PrintInformation->Margins->children($this->gnm, true) as $key => $margin) {
$marginAttributes = $margin->attributes();
$marginSize = ($marginAttributes['Points']) ?? 72; // Default is 72pt
// Convert value in points to inches
$marginSize = PageMargins::fromPoints((float) $marginSize);
$marginSet[$key] = $marginSize;
}

return $marginSet;
}

private function adjustMargins(array $marginSet): void
{
foreach ($marginSet as $key => $marginSize) {
// Gnumeric is quirky in the way it displays the header/footer values:
// header is actually the sum of top and header; footer is actually the sum of bottom and footer
// then top is actually the header value, and bottom is actually the footer value
switch ($key) {
case 'left':
case 'right':
$this->sheetMargin($key, $marginSize);

break;
case 'top':
$this->sheetMargin($key, $marginSet['header'] ?? 0);

break;
case 'bottom':
$this->sheetMargin($key, $marginSet['footer'] ?? 0);

break;
case 'header':
$this->sheetMargin($key, ($marginSet['top'] ?? 0) - $marginSize);

break;
case 'footer':
$this->sheetMargin($key, ($marginSet['bottom'] ?? 0) - $marginSize);

break;
}
}
}

private function sheetMargin(string $key, float $marginSize): void
{
switch ($key) {
case 'top':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setTop($marginSize);

break;
case 'bottom':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setBottom($marginSize);

break;
case 'left':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setLeft($marginSize);

break;
case 'right':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setRight($marginSize);

break;
case 'header':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setHeader($marginSize);

break;
case 'footer':
$this->spreadsheet->getActiveSheet()->getPageMargins()->setFooter($marginSize);

break;
}
}
}
22 changes: 20 additions & 2 deletions src/PhpSpreadsheet/Reader/Ods.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Reader\Ods\PageSettings;
use PhpOffice\PhpSpreadsheet\Reader\Ods\Properties as DocumentProperties;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
Expand Down Expand Up @@ -276,7 +277,17 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)

(new DocumentProperties($spreadsheet))->load($xml, $namespacesMeta);

// Content
// Styles

$dom = new DOMDocument('1.01', 'UTF-8');
$dom->loadXML(
$this->securityScanner->scan($zip->getFromName('styles.xml')),
Settings::getLibXmlLoaderOptions()
);

$pageSettings = new PageSettings($dom);

// Main Content

$dom = new DOMDocument('1.01', 'UTF-8');
$dom->loadXML(
Expand All @@ -289,6 +300,10 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
$textNs = $dom->lookupNamespaceUri('text');
$xlinkNs = $dom->lookupNamespaceUri('xlink');

$pageSettings->readStyleCrossReferences($dom);

// Content

$spreadsheets = $dom->getElementsByTagNameNS($officeNs, 'body')
->item(0)
->getElementsByTagNameNS($officeNs, 'spreadsheet');
Expand All @@ -309,6 +324,8 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
continue;
}

$worksheetStyleName = $worksheetDataSet->getAttributeNS($tableNs, 'style-name');

// Create sheet
if ($worksheetID > 0) {
$spreadsheet->createSheet(); // First sheet is added by default
Expand All @@ -319,7 +336,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
// Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in
// formula cells... during the load, all formulae should be correct, and we're simply
// bringing the worksheet name in line with the formula, not the reverse
$spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false);
$spreadsheet->getActiveSheet()->setTitle((string) $worksheetName, false, false);
}

// Go through every child of table element
Expand Down Expand Up @@ -641,6 +658,7 @@ public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet)
break;
}
}
$pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName);
++$worksheetID;
}
}
Expand Down
Loading