Merge pull request #1559 from PHPOffice/Page-Setup-Page-Order

Support pageOrder in page setup for Xlsx/Xls Readers/Writers, and implement basic page setup support for other Readers/Writers
This commit is contained in:
Adrien Crivelli 2020-07-26 12:00:25 +09:00 committed by GitHub
commit bd66a58203
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 1593 additions and 65 deletions

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added ### Added
- 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)
- Implementation of the Excel `LOGNORM.DIST()`, `NORM.S.DIST()`, `GAMMA()` and `GAUSS()` functions. [#1588](https://github.com/PHPOffice/PhpSpreadsheet/pull/1588) - Implementation of the Excel `LOGNORM.DIST()`, `NORM.S.DIST()`, `GAMMA()` and `GAUSS()` functions. [#1588](https://github.com/PHPOffice/PhpSpreadsheet/pull/1588)
### Changed ### Changed

View File

@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\NamedRange; use PhpOffice\PhpSpreadsheet\NamedRange;
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric\PageSetup;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\ReferenceHelper; use PhpOffice\PhpSpreadsheet\ReferenceHelper;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
@ -23,6 +24,8 @@ use XMLReader;
class Gnumeric extends BaseReader class Gnumeric extends BaseReader
{ {
private const UOM_CONVERSION_POINTS_TO_CENTIMETERS = 0.03527777778;
/** /**
* Shared Expressions. * Shared Expressions.
* *
@ -401,53 +404,6 @@ class Gnumeric extends BaseReader
} }
} }
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 private function processComments(SimpleXMLElement $sheet): void
{ {
if ((!$this->readDataOnly) && (isset($sheet->Objects))) { if ((!$this->readDataOnly) && (isset($sheet->Objects))) {
@ -513,7 +469,11 @@ class Gnumeric extends BaseReader
// name in line with the formula, not the reverse // name in line with the formula, not the reverse
$this->spreadsheet->getActiveSheet()->setTitle($worksheetName, false, false); $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) { foreach ($sheet->Cells->Cell as $cell) {
$cellAttributes = $cell->attributes(); $cellAttributes = $cell->attributes();

View File

@ -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, string $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;
}
}
}

View File

@ -11,6 +11,7 @@ use DOMNode;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Reader\Ods\PageSettings;
use PhpOffice\PhpSpreadsheet\Reader\Ods\Properties as DocumentProperties; use PhpOffice\PhpSpreadsheet\Reader\Ods\Properties as DocumentProperties;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
@ -276,7 +277,17 @@ class Ods extends BaseReader
(new DocumentProperties($spreadsheet))->load($xml, $namespacesMeta); (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 = new DOMDocument('1.01', 'UTF-8');
$dom->loadXML( $dom->loadXML(
@ -289,6 +300,10 @@ class Ods extends BaseReader
$textNs = $dom->lookupNamespaceUri('text'); $textNs = $dom->lookupNamespaceUri('text');
$xlinkNs = $dom->lookupNamespaceUri('xlink'); $xlinkNs = $dom->lookupNamespaceUri('xlink');
$pageSettings->readStyleCrossReferences($dom);
// Content
$spreadsheets = $dom->getElementsByTagNameNS($officeNs, 'body') $spreadsheets = $dom->getElementsByTagNameNS($officeNs, 'body')
->item(0) ->item(0)
->getElementsByTagNameNS($officeNs, 'spreadsheet'); ->getElementsByTagNameNS($officeNs, 'spreadsheet');
@ -309,6 +324,8 @@ class Ods extends BaseReader
continue; continue;
} }
$worksheetStyleName = $worksheetDataSet->getAttributeNS($tableNs, 'style-name');
// Create sheet // Create sheet
if ($worksheetID > 0) { if ($worksheetID > 0) {
$spreadsheet->createSheet(); // First sheet is added by default $spreadsheet->createSheet(); // First sheet is added by default
@ -319,7 +336,7 @@ class Ods extends BaseReader
// Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in // 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 // 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 // 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 // Go through every child of table element
@ -641,6 +658,7 @@ class Ods extends BaseReader
break; break;
} }
} }
$pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName);
++$worksheetID; ++$worksheetID;
} }
} }

View File

@ -0,0 +1,139 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Reader\Ods;
use DOMDocument;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class PageSettings
{
private $officeNs;
private $stylesNs;
private $stylesFo;
private $pageLayoutStyles = [];
private $masterStylesCrossReference = [];
private $masterPrintStylesCrossReference = [];
public function __construct(DOMDocument $styleDom)
{
$this->setDomNameSpaces($styleDom);
$this->readPageSettingStyles($styleDom);
$this->readStyleMasterLookup($styleDom);
}
private function setDomNameSpaces(DOMDocument $styleDom): void
{
$this->officeNs = $styleDom->lookupNamespaceUri('office');
$this->stylesNs = $styleDom->lookupNamespaceUri('style');
$this->stylesFo = $styleDom->lookupNamespaceUri('fo');
}
private function readPageSettingStyles(DOMDocument $styleDom): void
{
$styles = $styleDom->getElementsByTagNameNS($this->officeNs, 'automatic-styles')
->item(0)
->getElementsByTagNameNS($this->stylesNs, 'page-layout');
foreach ($styles as $styleSet) {
$styleName = $styleSet->getAttributeNS($this->stylesNs, 'name');
$pageLayoutProperties = $styleSet->getElementsByTagNameNS($this->stylesNs, 'page-layout-properties')[0];
$styleOrientation = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'print-orientation');
$styleScale = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'scale-to');
$stylePrintOrder = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'print-page-order');
$centered = $pageLayoutProperties->getAttributeNS($this->stylesNs, 'table-centering');
$marginLeft = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-left');
$marginRight = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-right');
$marginTop = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-top');
$marginBottom = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-bottom');
$header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')[0];
$headerProperties = $header->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0];
$marginHeader = $headerProperties->getAttributeNS($this->stylesFo, 'min-height');
$footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')[0];
$footerProperties = $footer->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0];
$marginFooter = $footerProperties->getAttributeNS($this->stylesFo, 'min-height');
$this->pageLayoutStyles[$styleName] = (object) [
'orientation' => $styleOrientation ?: PageSetup::ORIENTATION_DEFAULT,
'scale' => $styleScale ?: 100,
'printOrder' => $stylePrintOrder,
'horizontalCentered' => $centered === 'horizontal' || $centered === 'both',
'verticalCentered' => $centered === 'vertical' || $centered === 'both',
// margin size is already stored in inches, so no UOM conversion is required
'marginLeft' => (float) $marginLeft ?? 0.7,
'marginRight' => (float) $marginRight ?? 0.7,
'marginTop' => (float) $marginTop ?? 0.3,
'marginBottom' => (float) $marginBottom ?? 0.3,
'marginHeader' => (float) $marginHeader ?? 0.45,
'marginFooter' => (float) $marginFooter ?? 0.45,
];
}
}
private function readStyleMasterLookup(DOMDocument $styleDom): void
{
$styleMasterLookup = $styleDom->getElementsByTagNameNS($this->officeNs, 'master-styles')
->item(0)
->getElementsByTagNameNS($this->stylesNs, 'master-page');
foreach ($styleMasterLookup as $styleMasterSet) {
$styleMasterName = $styleMasterSet->getAttributeNS($this->stylesNs, 'name');
$pageLayoutName = $styleMasterSet->getAttributeNS($this->stylesNs, 'page-layout-name');
$this->masterPrintStylesCrossReference[$styleMasterName] = $pageLayoutName;
}
}
public function readStyleCrossReferences(DOMDocument $contentDom): void
{
$styleXReferences = $contentDom->getElementsByTagNameNS($this->officeNs, 'automatic-styles')
->item(0)
->getElementsByTagNameNS($this->stylesNs, 'style');
foreach ($styleXReferences as $styleXreferenceSet) {
$styleXRefName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'name');
$stylePageLayoutName = $styleXreferenceSet->getAttributeNS($this->stylesNs, 'master-page-name');
if (!empty($stylePageLayoutName)) {
$this->masterStylesCrossReference[$styleXRefName] = $stylePageLayoutName;
}
}
}
public function setPrintSettingsForWorksheet(Worksheet $worksheet, string $styleName): void
{
if (!array_key_exists($styleName, $this->masterStylesCrossReference)) {
return;
}
$masterStyleName = $this->masterStylesCrossReference[$styleName];
if (!array_key_exists($masterStyleName, $this->masterPrintStylesCrossReference)) {
return;
}
$printSettingsIndex = $this->masterPrintStylesCrossReference[$masterStyleName];
if (!array_key_exists($printSettingsIndex, $this->pageLayoutStyles)) {
return;
}
$printSettings = $this->pageLayoutStyles[$printSettingsIndex];
$worksheet->getPageSetup()
->setOrientation($printSettings->orientation ?? PageSetup::ORIENTATION_DEFAULT)
->setPageOrder($printSettings->printOrder === 'ltr' ? PageSetup::PAGEORDER_OVER_THEN_DOWN : PageSetup::PAGEORDER_DOWN_THEN_OVER)
->setScale((int) trim($printSettings->scale, '%'))
->setHorizontalCentered($printSettings->horizontalCentered)
->setVerticalCentered($printSettings->verticalCentered);
$worksheet->getPageMargins()
->setLeft($printSettings->marginLeft)
->setRight($printSettings->marginRight)
->setTop($printSettings->marginTop)
->setBottom($printSettings->marginBottom)
->setHeader($printSettings->marginHeader)
->setFooter($printSettings->marginFooter);
}
}

View File

@ -3444,6 +3444,9 @@ class Xls extends BaseReader
// offset: 10; size: 2; option flags // offset: 10; size: 2; option flags
// bit: 0; mask: 0x0001; 0=down then over, 1=over then down
$isOverThenDown = (0x0001 & self::getUInt2d($recordData, 10));
// bit: 1; mask: 0x0002; 0=landscape, 1=portrait // bit: 1; mask: 0x0002; 0=landscape, 1=portrait
$isPortrait = (0x0002 & self::getUInt2d($recordData, 10)) >> 1; $isPortrait = (0x0002 & self::getUInt2d($recordData, 10)) >> 1;
@ -3453,16 +3456,8 @@ class Xls extends BaseReader
if (!$isNotInit) { if (!$isNotInit) {
$this->phpSheet->getPageSetup()->setPaperSize($paperSize); $this->phpSheet->getPageSetup()->setPaperSize($paperSize);
switch ($isPortrait) { $this->phpSheet->getPageSetup()->setPageOrder(((bool) $isOverThenDown) ? PageSetup::PAGEORDER_OVER_THEN_DOWN : PageSetup::PAGEORDER_DOWN_THEN_OVER);
case 0: $this->phpSheet->getPageSetup()->setOrientation(((bool) $isPortrait) ? PageSetup::ORIENTATION_PORTRAIT : PageSetup::ORIENTATION_LANDSCAPE);
$this->phpSheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
break;
case 1:
$this->phpSheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_PORTRAIT);
break;
}
$this->phpSheet->getPageSetup()->setScale($scale, false); $this->phpSheet->getPageSetup()->setScale($scale, false);
$this->phpSheet->getPageSetup()->setFitToPage((bool) $this->isFitToPages); $this->phpSheet->getPageSetup()->setFitToPage((bool) $this->isFitToPages);

View File

@ -69,6 +69,9 @@ class PageSetup extends BaseParserClass
self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) { self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) {
$docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber'])); $docPageSetup->setFirstPageNumber((int) ($xmlSheet->pageSetup['firstPageNumber']));
} }
if (isset($xmlSheet->pageSetup['pageOrder'])) {
$docPageSetup->setPageOrder((string) $xmlSheet->pageSetup['pageOrder']);
}
$relAttributes = $xmlSheet->pageSetup->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $relAttributes = $xmlSheet->pageSetup->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships');
if (isset($relAttributes['id'])) { if (isset($relAttributes['id'])) {

View File

@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Document\Properties; use PhpOffice\PhpSpreadsheet\Document\Properties;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\Reader\Xml\PageSettings;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Settings;
use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Shared\Date;
@ -569,7 +570,7 @@ class Xml extends BaseReader
$columnReference = $columnNumber; $columnReference = $columnNumber;
} }
// Bracketed C references are relative to the current column // Bracketed C references are relative to the current column
if ($columnReference[0] == '[') { if (is_string($columnReference) && $columnReference[0] == '[') {
$columnReference = $columnNumber + trim($columnReference, '[]'); $columnReference = $columnNumber + trim($columnReference, '[]');
} }
$A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference; $A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference;
@ -626,6 +627,11 @@ class Xml extends BaseReader
++$rowID; ++$rowID;
} }
$xmlX = $worksheet->children($namespaces['x']);
if (isset($xmlX->WorksheetOptions)) {
(new PageSettings($xmlX, $namespaces))->loadPageSettings($spreadsheet);
}
} }
++$worksheetID; ++$worksheetID;
} }

View File

@ -0,0 +1,130 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Reader\Xml;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use SimpleXMLElement;
use stdClass;
class PageSettings
{
/**
* @var stdClass
*/
private $printSettings;
public function __construct(SimpleXMLElement $xmlX, array $namespaces)
{
$printSettings = $this->pageSetup($xmlX, $namespaces, $this->getPrintDefaults());
$this->printSettings = $this->printSetup($xmlX, $printSettings);
}
public function loadPageSettings(Spreadsheet $spreadsheet): void
{
$spreadsheet->getActiveSheet()->getPageSetup()
->setPaperSize($this->printSettings->paperSize)
->setOrientation($this->printSettings->orientation)
->setScale($this->printSettings->scale)
->setVerticalCentered($this->printSettings->verticalCentered)
->setHorizontalCentered($this->printSettings->horizontalCentered)
->setPageOrder($this->printSettings->printOrder);
$spreadsheet->getActiveSheet()->getPageMargins()
->setTop($this->printSettings->topMargin)
->setHeader($this->printSettings->headerMargin)
->setLeft($this->printSettings->leftMargin)
->setRight($this->printSettings->rightMargin)
->setBottom($this->printSettings->bottomMargin)
->setFooter($this->printSettings->footerMargin);
}
private function getPrintDefaults(): stdClass
{
return (object) [
'paperSize' => 9,
'orientation' => PageSetup::ORIENTATION_DEFAULT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'printOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
'topMargin' => 0.75,
'headerMargin' => 0.3,
'leftMargin' => 0.7,
'rightMargin' => 0.7,
'bottomMargin' => 0.75,
'footerMargin' => 0.3,
];
}
private function pageSetup(SimpleXMLElement $xmlX, array $namespaces, stdClass $printDefaults): stdClass
{
if (isset($xmlX->WorksheetOptions->PageSetup)) {
foreach ($xmlX->WorksheetOptions->PageSetup as $pageSetupData) {
foreach ($pageSetupData as $pageSetupKey => $pageSetupValue) {
$pageSetupAttributes = $pageSetupValue->attributes($namespaces['x']);
switch ($pageSetupKey) {
case 'Layout':
$this->setLayout($printDefaults, $pageSetupAttributes);
break;
case 'Header':
$printDefaults->headerMargin = (float) $pageSetupAttributes->Margin ?: 1.0;
break;
case 'Footer':
$printDefaults->footerMargin = (float) $pageSetupAttributes->Margin ?: 1.0;
break;
case 'PageMargins':
$this->setMargins($printDefaults, $pageSetupAttributes);
break;
}
}
}
}
return $printDefaults;
}
private function printSetup(SimpleXMLElement $xmlX, stdClass $printDefaults): stdClass
{
if (isset($xmlX->WorksheetOptions->Print)) {
foreach ($xmlX->WorksheetOptions->Print as $printData) {
foreach ($printData as $printKey => $printValue) {
switch ($printKey) {
case 'LeftToRight':
$printDefaults->printOrder = PageSetup::PAGEORDER_OVER_THEN_DOWN;
break;
case 'PaperSizeIndex':
$printDefaults->paperSize = (int) $printValue ?: 9;
break;
case 'Scale':
$printDefaults->scale = (int) $printValue ?: 100;
break;
}
}
}
}
return $printDefaults;
}
private function setLayout(stdClass $printDefaults, SimpleXMLElement $pageSetupAttributes): void
{
$printDefaults->orientation = (string) strtolower($pageSetupAttributes->Orientation) ?: PageSetup::ORIENTATION_PORTRAIT;
$printDefaults->horizontalCentered = (bool) $pageSetupAttributes->CenterHorizontal ?: false;
$printDefaults->verticalCentered = (bool) $pageSetupAttributes->CenterVertical ?: false;
}
private function setMargins(stdClass $printDefaults, SimpleXMLElement $pageSetupAttributes): void
{
$printDefaults->leftMargin = (float) $pageSetupAttributes->Left ?: 1.0;
$printDefaults->rightMargin = (float) $pageSetupAttributes->Right ?: 1.0;
$printDefaults->topMargin = (float) $pageSetupAttributes->Top ?: 1.0;
$printDefaults->bottomMargin = (float) $pageSetupAttributes->Bottom ?: 1.0;
}
}

View File

@ -211,4 +211,34 @@ class PageMargins
} }
} }
} }
public static function fromCentimeters(float $value): float
{
return $value / 2.54;
}
public static function toCentimeters(float $value): float
{
return $value * 2.54;
}
public static function fromMillimeters(float $value): float
{
return $value / 25.4;
}
public static function toMillimeters(float $value): float
{
return $value * 25.4;
}
public static function fromPoints(float $value): float
{
return $value / 72;
}
public static function toPoints(float $value): float
{
return $value * 72;
}
} }

View File

@ -156,6 +156,9 @@ class PageSetup
const SETPRINTRANGE_OVERWRITE = 'O'; const SETPRINTRANGE_OVERWRITE = 'O';
const SETPRINTRANGE_INSERT = 'I'; const SETPRINTRANGE_INSERT = 'I';
const PAGEORDER_OVER_THEN_DOWN = 'overThenDown';
const PAGEORDER_DOWN_THEN_OVER = 'downThenOver';
/** /**
* Paper size. * Paper size.
* *
@ -246,6 +249,8 @@ class PageSetup
*/ */
private $firstPageNumber; private $firstPageNumber;
private $pageOrder = self::PAGEORDER_DOWN_THEN_OVER;
/** /**
* Create a new PageSetup. * Create a new PageSetup.
*/ */
@ -818,6 +823,20 @@ class PageSetup
return $this->setFirstPageNumber(null); return $this->setFirstPageNumber(null);
} }
public function getPageOrder(): string
{
return $this->pageOrder;
}
public function setPageOrder(?string $pageOrder): self
{
if ($pageOrder === null || $pageOrder === self::PAGEORDER_DOWN_THEN_OVER || $pageOrder === self::PAGEORDER_OVER_THEN_DOWN) {
$this->pageOrder = $pageOrder ?? self::PAGEORDER_DOWN_THEN_OVER;
}
return $this;
}
/** /**
* Implement PHP __clone to create a deep clone, not just a shallow copy. * Implement PHP __clone to create a deep clone, not just a shallow copy.
*/ */

View File

@ -1729,11 +1729,12 @@ class Worksheet extends BIFFwriter
$numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin
$iCopies = 0x01; // Number of copies $iCopies = 0x01; // Number of copies
$fLeftToRight = 0x0; // Print over then down // Order of printing pages
$fLeftToRight = $this->phpSheet->getPageSetup()->getPageOrder() === PageSetup::PAGEORDER_DOWN_THEN_OVER
? 0x1 : 0x0;
// Page orientation // Page orientation
$fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ? $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE)
0x0 : 0x1; ? 0x0 : 0x1;
$fNoPls = 0x0; // Setup not read from printer $fNoPls = 0x0; // Setup not read from printer
$fNoColor = 0x0; // Print black and white $fNoColor = 0x0; // Print black and white

View File

@ -875,6 +875,7 @@ class Worksheet extends WriterPart
$objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber()); $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber());
$objWriter->writeAttribute('useFirstPageNumber', '1'); $objWriter->writeAttribute('useFirstPageNumber', '1');
} }
$objWriter->writeAttribute('pageOrder', $pSheet->getPageSetup()->getPageOrder());
$getUnparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData(); $getUnparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData();
if (isset($getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId'])) { if (isset($getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId'])) {

View File

@ -0,0 +1,147 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Gnumeric;
use PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PHPUnit\Framework\TestCase;
class PageSetupTest extends TestCase
{
private const MARGIN_PRECISION = 0.001;
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setup(): void
{
$filename = 'tests/data/Reader/Gnumeric/PageSetup.gnumeric';
$reader = new Gnumeric();
$this->spreadsheet = $reader->load($filename);
}
public function testPageSetup(): void
{
$assertions = $this->pageSetupAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageSetup()->$testMethodName();
self::assertSame(
$expectedResult,
$actualResult,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}"
);
}
}
}
public function testPageMargins(): void
{
$assertions = $this->pageMarginAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageMargins()->$testMethodName();
self::assertEqualsWithDelta(
$expectedResult,
$actualResult,
self::MARGIN_PRECISION,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin"
);
}
}
}
private function pageSetupAssertions(): array
{
return [
'Sheet1' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 75,
'horizontalCentered' => true,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet2' => [
'orientation' => PageSetup::ORIENTATION_LANDSCAPE,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_OVER_THEN_DOWN,
],
'Sheet3' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 90,
'horizontalCentered' => true,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet4' => [
// Default Settings
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
];
}
private function pageMarginAssertions(): array
{
return [
'Sheet1' => [
// Here the values are in inches
'top' => 0.315,
'header' => 0.630,
'left' => 0.512,
'right' => 0.512,
'bottom' => 0.315,
'footer' => 0.433,
],
'Sheet2' => [
// Here the values are in inches
'top' => 0.315,
'header' => 0.433,
'left' => 0.709,
'right' => 0.709,
'bottom' => 0.315,
'footer' => 0.433,
],
'Sheet3' => [
// Here the values are in inches
'top' => 0.512,
'header' => 0.433,
'left' => 0.709,
'right' => 0.709,
'bottom' => 0.512,
'footer' => 0.433,
],
'Sheet4' => [
// Default Settings (in inches)
'top' => 0.3,
'header' => 0.45,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.3,
'footer' => 0.45,
],
];
}
}

View File

@ -0,0 +1,149 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Reader\Ods;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PHPUnit\Framework\TestCase;
class PageSetupTest extends TestCase
{
private const MARGIN_PRECISION = 0.00000001;
private const MARGIN_UNIT_CONVERSION = 2.54; // Inches to cm
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setup(): void
{
$filename = 'tests/data/Reader/Ods/PageSetup.ods';
$reader = new Ods();
$this->spreadsheet = $reader->load($filename);
}
public function testPageSetup(): void
{
$assertions = $this->pageSetupAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageSetup()->$testMethodName();
self::assertSame(
$expectedResult,
$actualResult,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}"
);
}
}
}
public function testPageMargins(): void
{
$assertions = $this->pageMarginAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageMargins()->$testMethodName();
self::assertEqualsWithDelta(
$expectedResult,
$actualResult,
self::MARGIN_PRECISION,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin"
);
}
}
}
private function pageSetupAssertions(): array
{
return [
'Sheet1' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 75,
'horizontalCentered' => true,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet2' => [
'orientation' => PageSetup::ORIENTATION_LANDSCAPE,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_OVER_THEN_DOWN,
],
'Sheet3' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 90,
'horizontalCentered' => true,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet4' => [
// Default Settings
'orientation' => PageSetup::ORIENTATION_DEFAULT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
];
}
private function pageMarginAssertions(): array
{
return [
'Sheet1' => [
// Here the values are in cm
'top' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.6 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.1 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet2' => [
// Here the values are in cm
'top' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.1 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.1 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet3' => [
// Here the values are in cm
'top' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.1 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.1 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet4' => [
// Default Settings (already in inches)
'top' => 0.3,
'header' => 0.45,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.3,
'footer' => 0.45,
],
];
}
}

View File

@ -0,0 +1,149 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Reader\Xls;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PHPUnit\Framework\TestCase;
class PageSetupTest extends TestCase
{
private const MARGIN_PRECISION = 0.00000001;
private const MARGIN_UNIT_CONVERSION = 2.54; // Inches to cm
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setup(): void
{
$filename = 'tests/data/Reader/XLS/PageSetup.xls';
$reader = new Xls();
$this->spreadsheet = $reader->load($filename);
}
public function testPageSetup(): void
{
$assertions = $this->pageSetupAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageSetup()->$testMethodName();
self::assertSame(
$expectedResult,
$actualResult,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}"
);
}
}
}
public function testPageMargins(): void
{
$assertions = $this->pageMarginAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageMargins()->$testMethodName();
self::assertEqualsWithDelta(
$expectedResult,
$actualResult,
self::MARGIN_PRECISION,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin"
);
}
}
}
private function pageSetupAssertions(): array
{
return [
'Sheet1' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 75,
'horizontalCentered' => true,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet2' => [
'orientation' => PageSetup::ORIENTATION_LANDSCAPE,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_OVER_THEN_DOWN,
],
'Sheet3' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 90,
'horizontalCentered' => true,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet4' => [
// Default Settings
'orientation' => PageSetup::ORIENTATION_DEFAULT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
];
}
private function pageMarginAssertions(): array
{
return [
'Sheet1' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet2' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet3' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.3 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet4' => [
// Default Settings (already in inches for comparison)
'top' => 0.75,
'header' => 0.3,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.75,
'footer' => 0.3,
],
];
}
}

View File

@ -0,0 +1,149 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PHPUnit\Framework\TestCase;
class PageSetupTest extends TestCase
{
private const MARGIN_PRECISION = 0.00000001;
private const MARGIN_UNIT_CONVERSION = 2.54; // Inches to cm
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setup(): void
{
$filename = 'tests/data/Reader/XLSX/PageSetup.xlsx';
$reader = new Xlsx();
$this->spreadsheet = $reader->load($filename);
}
public function testPageSetup(): void
{
$assertions = $this->pageSetupAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageSetup()->$testMethodName();
self::assertSame(
$expectedResult,
$actualResult,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}"
);
}
}
}
public function testPageMargins(): void
{
$assertions = $this->pageMarginAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageMargins()->$testMethodName();
self::assertEqualsWithDelta(
$expectedResult,
$actualResult,
self::MARGIN_PRECISION,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin"
);
}
}
}
private function pageSetupAssertions(): array
{
return [
'Sheet1' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 75,
'horizontalCentered' => true,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet2' => [
'orientation' => PageSetup::ORIENTATION_LANDSCAPE,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_OVER_THEN_DOWN,
],
'Sheet3' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 90,
'horizontalCentered' => true,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet4' => [
// Default Settings
'orientation' => PageSetup::ORIENTATION_DEFAULT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
];
}
private function pageMarginAssertions(): array
{
return [
'Sheet1' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet2' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet3' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.3 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet4' => [
// Default Settings (already in inches for comparison)
'top' => 0.75,
'header' => 0.3,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.75,
'footer' => 0.3,
],
];
}
}

View File

@ -0,0 +1,149 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Reader\Xml;
use PhpOffice\PhpSpreadsheet\Reader\Xml;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
use PHPUnit\Framework\TestCase;
class PageSetupTest extends TestCase
{
private const MARGIN_PRECISION = 0.000001;
private const MARGIN_UNIT_CONVERSION = 2.54; // Inches to cm
/**
* @var Spreadsheet
*/
private $spreadsheet;
protected function setup(): void
{
$filename = 'tests/data/Reader/Xml/PageSetup.xml';
$reader = new Xml();
$this->spreadsheet = $reader->load($filename);
}
public function testPageSetup(): void
{
$assertions = $this->pageSetupAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageSetup()->$testMethodName();
self::assertSame(
$expectedResult,
$actualResult,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}"
);
}
}
}
public function testPageMargins(): void
{
$assertions = $this->pageMarginAssertions();
foreach ($this->spreadsheet->getAllSheets() as $worksheet) {
if (!array_key_exists($worksheet->getTitle(), $assertions)) {
continue;
}
$sheetAssertions = $assertions[$worksheet->getTitle()];
foreach ($sheetAssertions as $test => $expectedResult) {
$testMethodName = 'get' . ucfirst($test);
$actualResult = $worksheet->getPageMargins()->$testMethodName();
self::assertEqualsWithDelta(
$expectedResult,
$actualResult,
self::MARGIN_PRECISION,
"Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin"
);
}
}
}
private function pageSetupAssertions(): array
{
return [
'Sheet1' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 75,
'horizontalCentered' => true,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet2' => [
'orientation' => PageSetup::ORIENTATION_LANDSCAPE,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_OVER_THEN_DOWN,
],
'Sheet3' => [
'orientation' => PageSetup::ORIENTATION_PORTRAIT,
'scale' => 90,
'horizontalCentered' => true,
'verticalCentered' => true,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
'Sheet4' => [
// Default Settings
'orientation' => PageSetup::ORIENTATION_DEFAULT,
'scale' => 100,
'horizontalCentered' => false,
'verticalCentered' => false,
'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER,
],
];
}
private function pageMarginAssertions(): array
{
return [
'Sheet1' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet2' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'header' => 0.8 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 1.9 / self::MARGIN_UNIT_CONVERSION,
'footer' => 0.8 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet3' => [
// Here the values are in cm, so we convert to inches for comparison with internal uom
'top' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'header' => 1.3 / self::MARGIN_UNIT_CONVERSION,
'left' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'right' => 1.8 / self::MARGIN_UNIT_CONVERSION,
'bottom' => 2.4 / self::MARGIN_UNIT_CONVERSION,
'footer' => 1.3 / self::MARGIN_UNIT_CONVERSION,
],
'Sheet4' => [
// Default Settings (already in inches for comparison)
'top' => 0.75,
'header' => 0.3,
'left' => 0.7,
'right' => 0.7,
'bottom' => 0.75,
'footer' => 0.3,
],
];
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use PhpOffice\PhpSpreadsheet\Worksheet\PageMargins;
use PHPUnit\Framework\TestCase;
class PageMarginsTest extends TestCase
{
/**
* @dataProvider providerPointsAndInches
*/
public function testPointsToInches(float $value, float $expectedResult): void
{
$actualResult = PageMargins::fromPoints($value);
self::assertSame($expectedResult, $actualResult);
}
/**
* @dataProvider providerPointsAndInches
*/
public function testInchesToPoints(float $expectedResult, float $value): void
{
$actualResult = PageMargins::toPoints($value);
self::assertSame($expectedResult, $actualResult);
}
/**
* @dataProvider providerCentimetersAndInches
*/
public function testCentimetersToInches(float $value, float $expectedResult): void
{
$actualResult = PageMargins::fromCentimeters($value);
self::assertSame($expectedResult, $actualResult);
}
/**
* @dataProvider providerCentimetersAndInches
*/
public function testPointsToCentimeters(float $expectedResult, float $value): void
{
$actualResult = PageMargins::toCentimeters($value);
self::assertSame($expectedResult, $actualResult);
}
/**
* @dataProvider providerMillimetersAndInches
*/
public function testMillimetersToInches(float $value, float $expectedResult): void
{
$actualResult = PageMargins::fromMillimeters($value);
self::assertSame($expectedResult, $actualResult);
}
/**
* @dataProvider providerMillimetersAndInches
*/
public function testPointsToMillimeters(float $expectedResult, float $value): void
{
$actualResult = PageMargins::toMillimeters($value);
self::assertSame($expectedResult, $actualResult);
}
public function providerPointsAndInches(): array
{
return [
[36, 0.5],
[72, 1.0],
[90, 1.25],
[144, 2.0],
];
}
public function providerCentimetersAndInches(): array
{
return [
[1.27, 0.5],
[2.54, 1.0],
];
}
public function providerMillimetersAndInches(): array
{
return [
[12.7, 0.5],
[25.4, 1.0],
];
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,250 @@
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
<Author>Mark Baker</Author>
<LastAuthor>Mark Baker</LastAuthor>
<LastPrinted>2020-07-04T11:51:41Z</LastPrinted>
<Created>2020-06-29T17:37:00Z</Created>
<LastSaved>2020-07-04T11:52:32Z</LastSaved>
<Version>16.00</Version>
</DocumentProperties>
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<AllowPNG/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>13170</WindowHeight>
<WindowWidth>21600</WindowWidth>
<WindowTopX>2145</WindowTopX>
<WindowTopY>2145</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="14.25">
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">1</Data></Cell>
<Cell><Data ss:Type="Number">2</Data></Cell>
<Cell><Data ss:Type="Number">3</Data></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">4</Data></Cell>
<Cell><Data ss:Type="Number">5</Data></Cell>
<Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">7</Data></Cell>
<Cell><Data ss:Type="Number">8</Data></Cell>
<Cell><Data ss:Type="Number">9</Data></Cell>
</Row>
<Row ss:Index="5" ss:AutoFitHeight="0">
<Cell ss:Formula="=SUM(R[-3]C:R[-3]C[2],R[-4]C[1]:R[-2]C[1])"><Data
ss:Type="Number">30</Data></Cell>
<Cell ss:Formula="=COUNT(R[-3]C[-1]:R[-3]C[1],R[-4]C:R[-2]C)"><Data
ss:Type="Number">6</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Layout x:CenterHorizontal="1"/>
<Header x:Margin="0.31496062992125984"/>
<Footer x:Margin="0.31496062992125984"/>
<PageMargins x:Bottom="0.74803149606299213" x:Left="0.51181102362204722"
x:Right="0.51181102362204722" x:Top="0.94488188976377963"/>
</PageSetup>
<Unsynced/>
<Print>
<ValidPrinterInfo/>
<PaperSizeIndex>9</PaperSizeIndex>
<Scale>75</Scale>
<VerticalResolution>0</VerticalResolution>
</Print>
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<RangeSelection>R1C1:R5C3</RangeSelection>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet2">
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="14.25">
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">1</Data></Cell>
<Cell><Data ss:Type="Number">2</Data></Cell>
<Cell><Data ss:Type="Number">3</Data></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">4</Data></Cell>
<Cell><Data ss:Type="Number">5</Data></Cell>
<Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">7</Data></Cell>
<Cell><Data ss:Type="Number">8</Data></Cell>
<Cell><Data ss:Type="Number">9</Data></Cell>
</Row>
<Row ss:Index="5" ss:AutoFitHeight="0">
<Cell ss:Formula="=SUM(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">60</Data></Cell>
<Cell ss:Formula="=COUNT(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">12</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Layout x:Orientation="Landscape" x:CenterVertical="1"/>
<Header x:Margin="0.31496062992125984"/>
<Footer x:Margin="0.31496062992125984"/>
<PageMargins x:Bottom="0.74803149606299213" x:Left="0.70866141732283472"
x:Right="0.70866141732283472" x:Top="0.74803149606299213"/>
</PageSetup>
<Unsynced/>
<Print>
<LeftToRight/>
<ValidPrinterInfo/>
<PaperSizeIndex>9</PaperSizeIndex>
<VerticalResolution>0</VerticalResolution>
</Print>
<Panes>
<Pane>
<Number>3</Number>
<RangeSelection>R1C1:R5C3</RangeSelection>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet3">
<Names>
<NamedRange ss:Name="Print_Area" ss:RefersTo="=Sheet3!R1C1:R5C3"/>
</Names>
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="14.25">
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">1</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">2</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">3</Data><NamedCell ss:Name="Print_Area"/></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">4</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">5</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">6</Data><NamedCell ss:Name="Print_Area"/></Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell><Data ss:Type="Number">7</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">8</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell><Data ss:Type="Number">9</Data><NamedCell ss:Name="Print_Area"/></Cell>
</Row>
<Row ss:Index="5" ss:AutoFitHeight="0">
<Cell ss:Formula="=SUM(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">60</Data><NamedCell ss:Name="Print_Area"/></Cell>
<Cell ss:Formula="=COUNT(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">12</Data><NamedCell ss:Name="Print_Area"/></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Layout x:CenterHorizontal="1" x:CenterVertical="1"/>
<Header x:Margin="0.51181102362204722"/>
<Footer x:Margin="0.51181102362204722"/>
<PageMargins x:Bottom="0.94488188976377963" x:Left="0.70866141732283472"
x:Right="0.70866141732283472" x:Top="0.94488188976377963"/>
</PageSetup>
<Unsynced/>
<Print>
<ValidPrinterInfo/>
<PaperSizeIndex>9</PaperSizeIndex>
<Scale>90</Scale>
<VerticalResolution>0</VerticalResolution>
</Print>
<FreezePanes/>
<FrozenNoSplit/>
<SplitHorizontal>1</SplitHorizontal>
<TopRowBottomPane>1</TopRowBottomPane>
<SplitVertical>1</SplitVertical>
<LeftColumnRightPane>1</LeftColumnRightPane>
<ActivePane>0</ActivePane>
<Panes>
<Pane>
<Number>3</Number>
</Pane>
<Pane>
<Number>1</Number>
</Pane>
<Pane>
<Number>2</Number>
</Pane>
<Pane>
<Number>0</Number>
<ActiveRow>0</ActiveRow>
<ActiveCol>0</ActiveCol>
<RangeSelection>R1C1:R5C3</RangeSelection>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet4">
<Table ss:ExpandedColumnCount="3" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="51" ss:DefaultRowHeight="14.25">
<Row>
<Cell><Data ss:Type="Number">1</Data></Cell>
<Cell><Data ss:Type="Number">2</Data></Cell>
<Cell><Data ss:Type="Number">3</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">4</Data></Cell>
<Cell><Data ss:Type="Number">5</Data></Cell>
<Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="Number">7</Data></Cell>
<Cell><Data ss:Type="Number">8</Data></Cell>
<Cell><Data ss:Type="Number">9</Data></Cell>
</Row>
<Row ss:Index="5">
<Cell ss:Formula="=SUM(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">60</Data></Cell>
<Cell ss:Formula="=COUNT(R1C1:R1C3,R3C1:R3C3,R1C1:R3C1,R1C3:R3C3)"><Data
ss:Type="Number">12</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Panes>
<Pane>
<Number>3</Number>
<RangeSelection>R1C1:R5C3</RangeSelection>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>