diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0d4c91..439eb7d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### 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) ### Changed diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index 81096730..a29a2b9d 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader; 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; @@ -23,6 +24,8 @@ use XMLReader; class Gnumeric extends BaseReader { + private const UOM_CONVERSION_POINTS_TO_CENTIMETERS = 0.03527777778; + /** * 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 { if ((!$this->readDataOnly) && (isset($sheet->Objects))) { @@ -513,7 +469,11 @@ class Gnumeric extends BaseReader // 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(); diff --git a/src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php b/src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php new file mode 100644 index 00000000..0fe73005 --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php @@ -0,0 +1,143 @@ +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; + } + } +} diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index d638d1fb..4f164b6f 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -11,6 +11,7 @@ use DOMNode; 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; @@ -276,7 +277,17 @@ class Ods extends BaseReader (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( @@ -289,6 +300,10 @@ class Ods extends BaseReader $textNs = $dom->lookupNamespaceUri('text'); $xlinkNs = $dom->lookupNamespaceUri('xlink'); + $pageSettings->readStyleCrossReferences($dom); + + // Content + $spreadsheets = $dom->getElementsByTagNameNS($officeNs, 'body') ->item(0) ->getElementsByTagNameNS($officeNs, 'spreadsheet'); @@ -309,6 +324,8 @@ class Ods extends BaseReader continue; } + $worksheetStyleName = $worksheetDataSet->getAttributeNS($tableNs, 'style-name'); + // Create sheet if ($worksheetID > 0) { $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 // 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 @@ -641,6 +658,7 @@ class Ods extends BaseReader break; } } + $pageSettings->setPrintSettingsForWorksheet($spreadsheet->getActiveSheet(), $worksheetStyleName); ++$worksheetID; } } diff --git a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php new file mode 100644 index 00000000..77341aab --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php @@ -0,0 +1,139 @@ +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); + } +} diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 11a6195c..cdac07d0 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -3444,6 +3444,9 @@ class Xls extends BaseReader // 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 $isPortrait = (0x0002 & self::getUInt2d($recordData, 10)) >> 1; @@ -3453,16 +3456,8 @@ class Xls extends BaseReader if (!$isNotInit) { $this->phpSheet->getPageSetup()->setPaperSize($paperSize); - switch ($isPortrait) { - case 0: - $this->phpSheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE); - - break; - case 1: - $this->phpSheet->getPageSetup()->setOrientation(PageSetup::ORIENTATION_PORTRAIT); - - break; - } + $this->phpSheet->getPageSetup()->setPageOrder(((bool) $isOverThenDown) ? PageSetup::PAGEORDER_OVER_THEN_DOWN : PageSetup::PAGEORDER_DOWN_THEN_OVER); + $this->phpSheet->getPageSetup()->setOrientation(((bool) $isPortrait) ? PageSetup::ORIENTATION_PORTRAIT : PageSetup::ORIENTATION_LANDSCAPE); $this->phpSheet->getPageSetup()->setScale($scale, false); $this->phpSheet->getPageSetup()->setFitToPage((bool) $this->isFitToPages); diff --git a/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php b/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php index bfb7a1f5..b556703c 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php @@ -69,6 +69,9 @@ class PageSetup extends BaseParserClass self::boolean((string) $xmlSheet->pageSetup['useFirstPageNumber'])) { $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'); if (isset($relAttributes['id'])) { diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index f9ad5475..fc2f5108 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Document\Properties; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; +use PhpOffice\PhpSpreadsheet\Reader\Xml\PageSettings; use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheet\Shared\Date; @@ -569,7 +570,7 @@ class Xml extends BaseReader $columnReference = $columnNumber; } // Bracketed C references are relative to the current column - if ($columnReference[0] == '[') { + if (is_string($columnReference) && $columnReference[0] == '[') { $columnReference = $columnNumber + trim($columnReference, '[]'); } $A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference; @@ -626,6 +627,11 @@ class Xml extends BaseReader ++$rowID; } + + $xmlX = $worksheet->children($namespaces['x']); + if (isset($xmlX->WorksheetOptions)) { + (new PageSettings($xmlX, $namespaces))->loadPageSettings($spreadsheet); + } } ++$worksheetID; } diff --git a/src/PhpSpreadsheet/Reader/Xml/PageSettings.php b/src/PhpSpreadsheet/Reader/Xml/PageSettings.php new file mode 100644 index 00000000..e56ac331 --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Xml/PageSettings.php @@ -0,0 +1,130 @@ +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; + } +} diff --git a/src/PhpSpreadsheet/Worksheet/PageMargins.php b/src/PhpSpreadsheet/Worksheet/PageMargins.php index 9ebfb648..a8297933 100644 --- a/src/PhpSpreadsheet/Worksheet/PageMargins.php +++ b/src/PhpSpreadsheet/Worksheet/PageMargins.php @@ -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; + } } diff --git a/src/PhpSpreadsheet/Worksheet/PageSetup.php b/src/PhpSpreadsheet/Worksheet/PageSetup.php index f29dbad5..d8d5098f 100644 --- a/src/PhpSpreadsheet/Worksheet/PageSetup.php +++ b/src/PhpSpreadsheet/Worksheet/PageSetup.php @@ -156,6 +156,9 @@ class PageSetup const SETPRINTRANGE_OVERWRITE = 'O'; const SETPRINTRANGE_INSERT = 'I'; + const PAGEORDER_OVER_THEN_DOWN = 'overThenDown'; + const PAGEORDER_DOWN_THEN_OVER = 'downThenOver'; + /** * Paper size. * @@ -246,6 +249,8 @@ class PageSetup */ private $firstPageNumber; + private $pageOrder = self::PAGEORDER_DOWN_THEN_OVER; + /** * Create a new PageSetup. */ @@ -818,6 +823,20 @@ class PageSetup 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. */ diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index 0dce7ba5..eb6b479d 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -1729,11 +1729,12 @@ class Worksheet extends BIFFwriter $numFtr = $this->phpSheet->getPageMargins()->getFooter(); // Footer Margin $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 - $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) ? - 0x0 : 0x1; + $fLandscape = ($this->phpSheet->getPageSetup()->getOrientation() == PageSetup::ORIENTATION_LANDSCAPE) + ? 0x0 : 0x1; $fNoPls = 0x0; // Setup not read from printer $fNoColor = 0x0; // Print black and white diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index be064256..759d9611 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -875,6 +875,7 @@ class Worksheet extends WriterPart $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber()); $objWriter->writeAttribute('useFirstPageNumber', '1'); } + $objWriter->writeAttribute('pageOrder', $pSheet->getPageSetup()->getPageOrder()); $getUnparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData(); if (isset($getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId'])) { diff --git a/tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php new file mode 100644 index 00000000..0b563586 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php @@ -0,0 +1,147 @@ +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, + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php new file mode 100644 index 00000000..20af31c5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php @@ -0,0 +1,149 @@ +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, + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php new file mode 100644 index 00000000..034ce6ee --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php @@ -0,0 +1,149 @@ +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, + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php new file mode 100644 index 00000000..c00a1623 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php @@ -0,0 +1,149 @@ +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, + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php new file mode 100644 index 00000000..97476ed5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php @@ -0,0 +1,149 @@ +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, + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php b/tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php new file mode 100644 index 00000000..37b6df2b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php @@ -0,0 +1,89 @@ + + + + + Mark Baker + Mark Baker + 2020-07-04T11:51:41Z + 2020-06-29T17:37:00Z + 2020-07-04T11:52:32Z + 16.00 + + + + + + 13170 + 21600 + 2145 + 2145 + False + False + + + + + + + + 1 + 2 + 3 + + + 4 + 5 + 6 + + + 7 + 8 + 9 + + + 30 + 6 + +
+ + + +
+